[GRASS-SVN] r68243 - in grass-addons/grass7/vector: . v.stream.order v.stream.order/testsuite v.stream.order/testsuite/data

svn_grass at osgeo.org svn_grass at osgeo.org
Sun Apr 10 05:53:24 PDT 2016


Author: huhabla
Date: 2016-04-10 05:53:24 -0700 (Sun, 10 Apr 2016)
New Revision: 68243

Added:
   grass-addons/grass7/vector/v.stream.order/
   grass-addons/grass7/vector/v.stream.order/Makefile
   grass-addons/grass7/vector/v.stream.order/stream_network.png
   grass-addons/grass7/vector/v.stream.order/stream_network_order_drwal.png
   grass-addons/grass7/vector/v.stream.order/stream_network_order_scheidegger.png
   grass-addons/grass7/vector/v.stream.order/stream_network_order_shreve.png
   grass-addons/grass7/vector/v.stream.order/stream_network_order_strahler.png
   grass-addons/grass7/vector/v.stream.order/testsuite/
   grass-addons/grass7/vector/v.stream.order/testsuite/data/
   grass-addons/grass7/vector/v.stream.order/testsuite/data/stream_network.txt
   grass-addons/grass7/vector/v.stream.order/testsuite/data/stream_network_outlets.txt
   grass-addons/grass7/vector/v.stream.order/testsuite/generate_manpage_images.sh
   grass-addons/grass7/vector/v.stream.order/testsuite/generate_stream_outflow_points.sh
   grass-addons/grass7/vector/v.stream.order/testsuite/test_stream_order.py
   grass-addons/grass7/vector/v.stream.order/v.stream.order.html
   grass-addons/grass7/vector/v.stream.order/v.stream.order.py
Log:
New module to compute different stream orders on vector networks.
AUTHOR(S):    IGB-Berlin,Johannes Radinger; Implementation: Soeren Gebbert"

This tool was developed as part of the BiodivERsA-net project 'FISHCON'
and has been funded by the German Federal Ministry for Education and
Research (grant number 01LC1205).


Added: grass-addons/grass7/vector/v.stream.order/Makefile
===================================================================
--- grass-addons/grass7/vector/v.stream.order/Makefile	                        (rev 0)
+++ grass-addons/grass7/vector/v.stream.order/Makefile	2016-04-10 12:53:24 UTC (rev 68243)
@@ -0,0 +1,7 @@
+MODULE_TOPDIR = ../..
+
+PGM = v.stream.order
+
+include $(MODULE_TOPDIR)/include/Make/Script.make
+
+default: script

Added: grass-addons/grass7/vector/v.stream.order/stream_network.png
===================================================================
(Binary files differ)


Property changes on: grass-addons/grass7/vector/v.stream.order/stream_network.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass-addons/grass7/vector/v.stream.order/stream_network_order_drwal.png
===================================================================
(Binary files differ)


Property changes on: grass-addons/grass7/vector/v.stream.order/stream_network_order_drwal.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass-addons/grass7/vector/v.stream.order/stream_network_order_scheidegger.png
===================================================================
(Binary files differ)


Property changes on: grass-addons/grass7/vector/v.stream.order/stream_network_order_scheidegger.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass-addons/grass7/vector/v.stream.order/stream_network_order_shreve.png
===================================================================
(Binary files differ)


Property changes on: grass-addons/grass7/vector/v.stream.order/stream_network_order_shreve.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass-addons/grass7/vector/v.stream.order/stream_network_order_strahler.png
===================================================================
(Binary files differ)


Property changes on: grass-addons/grass7/vector/v.stream.order/stream_network_order_strahler.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass-addons/grass7/vector/v.stream.order/testsuite/data/stream_network.txt
===================================================================
--- grass-addons/grass7/vector/v.stream.order/testsuite/data/stream_network.txt	                        (rev 0)
+++ grass-addons/grass7/vector/v.stream.order/testsuite/data/stream_network.txt	2016-04-10 12:53:24 UTC (rev 68243)
@@ -0,0 +1,539 @@
+ORGANIZATION: 
+DIGIT DATE:   
+DIGIT NAME:   soeren
+MAP NAME:     
+MAP DATE:     Mon Nov 23 09:27:02 2015
+MAP SCALE:    1
+OTHER INFO:   
+ZONE:         0
+MAP THRESH:   0.000000
+VERTI:
+L  3 1
+ 641045.70521951 218398.66077254
+ 641049.6221644 218261.56770124
+ 641026.12049504 218155.8101891
+ 1     5         
+L  2 1
+ 640769.59784873 218298.21972805
+ 641026.12049504 218155.8101891
+ 1     4         
+L  2 1
+ 640587.42266689 218394.74382764
+ 640769.59784873 218298.21972805
+ 1     2         
+L  4 1
+ 641754.51490227 218445.12286994
+ 641813.68865794 218350.44486086
+ 641821.57849203 218216.31768133
+ 641801.85390681 218113.74983816
+ 1     6         
+L  4 1
+ 641801.85390681 218113.74983816
+ 641880.75224771 218192.64817906
+ 641999.09975906 218338.61010972
+ 642121.39218745 218409.61861653
+ 1     7         
+L  2 1
+ 640882.68823532 217640.35979276
+ 640866.90856714 217305.04184393
+ 1     9         
+L  4 1
+ 640397.46343879 217608.8004564
+ 640567.09487172 217525.95719845
+ 640701.22205125 217399.71985301
+ 640866.90856714 217305.04184393
+ 1     10        
+L  6 1
+ 640866.90856714 217305.04184393
+ 641008.92558076 217198.52908372
+ 641178.5570137 217044.67731896
+ 641296.90452505 216910.55013943
+ 641415.2520364 216851.37638376
+ 641456.98443339 216796.63031084
+ 1     11        
+L  2 1
+ 641613.66222916 217223.5773043
+ 641527.48944149 216965.05894128
+ 1     4         
+L  2 1
+ 641527.48944149 216965.05894128
+ 641456.98443339 216796.63031084
+ 1     4         
+L  3 1
+ 641527.48944149 216965.05894128
+ 641876.80733066 216886.88063716
+ 642089.83285109 216989.44848033
+ 1     12        
+L  2 1
+ 642610.56190103 216646.24069742
+ 642429.09571696 216807.98229626
+ 1     15        
+L  2 1
+ 642638.17632035 216875.04588603
+ 642429.09571696 216807.98229626
+ 1     14        
+L  4 1
+ 642429.09571696 216807.98229626
+ 642235.79478176 216851.37638376
+ 642129.28202154 216953.94422693
+ 642089.83285109 216989.44848033
+ 1     14        
+L  2 1
+ 641111.49342393 216523.94826902
+ 641570.57583532 216479.35777441
+ 1     16        
+L  2 1
+ 641456.98443339 216796.63031084
+ 641570.57583532 216479.35777441
+ 1     4         
+L  3 1
+ 642835.4221726 217356.32576552
+ 642752.57891465 217285.31725871
+ 642598.38529023 217185.55940265
+ 1     13        
+L  4 1
+ 642089.83285109 216989.44848033
+ 642243.68461585 217178.80449849
+ 642456.71013628 217218.25366894
+ 642598.38529023 217185.55940265
+ 1     12        
+L  3 1
+ 642598.38529023 217185.55940265
+ 642713.1297442 217159.07991327
+ 642870.926426 217092.0163235
+ 1     12        
+L  2 1
+ 642598.38529023 217185.55940265
+ 642598.38529023 217185.55940265
+ 1     13        
+L  6 1
+ 641756.22516769 217996.07572149
+ 641849.21322931 217926.33467527
+ 641910.86354075 217814.96637073
+ 641916.82969993 217504.72609381
+ 641795.51779677 217411.25626679
+ 641655.59356064 217351.01110956
+ 1     17        
+L  2 1
+ 641801.85390681 218113.74983816
+ 641756.22516769 217996.07572149
+ 1     8         
+L  2 1
+ 641655.59356064 217351.01110956
+ 641613.66222916 217223.5773043
+ 1     8         
+L  3 1
+ 641756.22516769 217996.07572149
+ 641726.90048295 217920.44890295
+ 641705.76772964 217817.13322006
+ 1     8         
+L  5 1
+ 641705.76772964 217817.13322006
+ 641691.39622955 217746.87255297
+ 641687.4513125 217573.29620299
+ 641667.72672728 217387.88510188
+ 641655.59356064 217351.01110956
+ 1     8         
+L  3 1
+ 641282.29449313 217827.21623271
+ 641499.52584836 217821.16315379
+ 641705.76772964 217817.13322006
+ 1     18        
+L  3 1
+ 641026.12049504 218155.8101891
+ 641268.97107847 217850.28848736
+ 641282.29449313 217827.21623271
+ 1     4         
+L  3 1
+ 641282.29449313 217827.21623271
+ 641429.56581913 217572.18539988
+ 641613.66222916 217223.5773043
+ 1     4         
+L  6 1
+ 641570.57583532 216479.35777441
+ 641974.02115942 216122.91578904
+ 642030.89764886 216016.47550165
+ 642034.11888304 216010.44719198
+ 642248.20730201 215609.79600791
+ 642659.48651589 215155.43040019
+ 1     4         
+L  4 1
+ 643891.13814168 216140.36775244
+ 643813.99670971 216258.10993807
+ 643700.31459945 216258.10993807
+ 643639.41346895 216262.17001344
+ 1     22        
+L  2 1
+ 643692.19444871 216505.77453544
+ 643639.41346895 216262.17001344
+ 1     21        
+L  3 1
+ 643639.41346895 216262.17001344
+ 643509.49105721 216176.90843074
+ 643347.08804255 216156.60805391
+ 1     21        
+L  4 1
+ 643168.44472642 215852.10240141
+ 643079.12306835 215982.02481314
+ 642932.96035515 216091.64684804
+ 642709.65620999 216180.96850611
+ 1     23        
+L  3 1
+ 643347.08804255 216156.60805391
+ 643225.28578155 215998.26511461
+ 643168.44472642 215852.10240141
+ 1     19        
+L  6 1
+ 643311.00699542 215576.83439857
+ 643347.08804255 215640.97848235
+ 643440.46977598 215734.36021578
+ 643574.45226308 215779.02104481
+ 643688.13437335 215787.14119555
+ 643773.39595605 215783.08112018
+ 1     24        
+L  3 1
+ 643168.44472642 215852.10240141
+ 643221.22570618 215681.57923601
+ 643311.00699542 215576.83439857
+ 1     19        
+L  5 1
+ 643311.00699542 215576.83439857
+ 643343.02796718 215539.47659818
+ 643448.58992672 215381.13365888
+ 643456.71007745 215234.97094568
+ 643424.22947452 215113.16868469
+ 1     19        
+L  4 1
+ 640567.86448829 216432.09912471
+ 640567.86448829 216226.52319892
+ 640600.75663642 216086.73156938
+ 640584.31056236 215971.60905094
+ 1     27        
+L  6 1
+ 640370.51159953 215511.11897717
+ 640641.87182158 215535.78808826
+ 640839.22471033 215486.44986607
+ 640913.23204362 215428.88860685
+ 641127.03100644 215346.65823654
+ 641127.03100644 215346.65823654
+ 1     28        
+L  4 1
+ 640773.44041408 215848.26349546
+ 640946.12419174 215700.24882889
+ 641044.80063612 215511.11897717
+ 641127.03100644 215346.65823654
+ 1     25        
+L  4 1
+ 641127.03100644 215346.65823654
+ 641283.26871004 215206.866607
+ 641571.07500615 215124.63623668
+ 641784.87396897 215108.19016262
+ 1     25        
+L  2 1
+ 640584.31056236 215971.60905094
+ 640773.44041408 215848.26349546
+ 1     29        
+L  2 1
+ 639498.86967419 217279.07193896
+ 639753.78382216 217163.94942052
+ 1     25        
+L  3 1
+ 639753.78382216 217163.94942052
+ 639975.80582202 216966.59653176
+ 640132.04352562 216687.01327269
+ 1     25        
+L  2 1
+ 640132.04352562 216687.01327269
+ 640214.27389593 216423.87608767
+ 1     25        
+L  2 1
+ 640132.04352562 216687.01327269
+ 640166.20300793 216826.57359053
+ 1     31        
+L  2 1
+ 640214.27389593 216423.87608767
+ 640370.51159953 216144.2928286
+ 1     25        
+L  2 1
+ 640370.51159953 216144.2928286
+ 640584.31056236 215971.60905094
+ 1     25        
+L  4 1
+ 639768.06562446 216349.33606465
+ 639696.87549629 216420.52619282
+ 639612.50201105 216504.89967806
+ 639483.30511178 216562.90644916
+ 1     34        
+L  5 1
+ 639768.06562446 216349.33606465
+ 639599.31865399 216367.79276455
+ 639422.66166927 216378.3394502
+ 639240.73134172 216373.06610737
+ 639185.36124204 216312.42266486
+ 1     33        
+L  5 1
+ 639768.06562446 216349.33606465
+ 639652.05208226 216315.05933627
+ 639512.30849733 216228.04917962
+ 639454.30172623 216104.12562318
+ 639420.02499786 215961.74536684
+ 1     35        
+L  3 1
+ 639420.02499786 215961.74536684
+ 639288.19142717 215819.3651105
+ 639166.90454214 215792.99839636
+ 1     35        
+L  4 1
+ 639628.32203954 215761.3583394
+ 639543.9485543 215782.45171071
+ 639480.66844037 215824.63845333
+ 639432.57555378 215849.9504989
+ 1     38        
+L  3 1
+ 639420.02499786 215961.74536684
+ 639417.38832644 215887.91856725
+ 639432.57555378 215849.9504989
+ 1     36        
+L  4 1
+ 639432.57555378 215849.9504989
+ 639449.02838341 215808.81842484
+ 639509.67182592 215721.80826819
+ 639538.67521147 215666.43816851
+ 1     36        
+L  4 1
+ 639936.81259494 215945.92533836
+ 639923.62923787 216048.75552349
+ 639942.08593777 216109.398966
+ 639957.90596625 216148.94903721
+ 1     39        
+L  2 1
+ 639786.52232436 215993.3854238
+ 639957.90596625 216148.94903721
+ 1     37        
+L  2 1
+ 639498.86967419 216777.46668003
+ 639720.89167404 216736.35149487
+ 1     26        
+L  4 1
+ 639720.89167404 216736.35149487
+ 639918.2445628 216645.89808753
+ 640156.71263671 216489.66038393
+ 640214.27389593 216423.87608767
+ 1     26        
+L  4 1
+ 639686.32881064 217048.05398928
+ 639678.4187964 216966.31717545
+ 639665.23543933 216892.49037587
+ 639665.23543933 216892.49037587
+ 1     41        
+L  3 1
+ 639443.75504058 217029.59728938
+ 639551.85856854 216968.95384687
+ 639665.23543933 216892.49037587
+ 1     40        
+L  3 1
+ 639665.23543933 216892.49037587
+ 639712.69552477 216821.3002477
+ 639720.89167404 216736.35149487
+ 1     40        
+L  2 1
+ 640545.8836915 216837.12027618
+ 640406.14010658 216781.7501765
+ 1     42        
+L  3 1
+ 640353.4066783 216897.7637187
+ 640414.05012082 216871.39700456
+ 640414.05012082 216871.39700456
+ 1     46        
+L  2 1
+ 640427.23347788 216929.40377566
+ 640414.05012082 216871.39700456
+ 1     45        
+L  3 1
+ 640414.05012082 216871.39700456
+ 640387.68340668 216818.66357629
+ 640406.14010658 216781.7501765
+ 1     45        
+L  2 1
+ 640166.20300793 217137.70081734
+ 640063.3728228 217311.72113065
+ 1     31        
+L  4 1
+ 640150.91939902 217380.57237139
+ 640179.08811888 217311.35780259
+ 640192.77006852 217286.40836501
+ 640202.42791533 217275.14087706
+ 1     49        
+L  2 1
+ 640257.15571392 217334.69759905
+ 640202.42791533 217275.14087706
+ 1     47        
+L  4 1
+ 640202.42791533 217275.14087706
+ 640173.45437491 217220.41307848
+ 640167.82063093 217153.61297138
+ 640166.20300793 217137.70081734
+ 1     47        
+L  4 1
+ 640313.49315364 217267.89749195
+ 640250.71714938 217238.11913096
+ 640209.67130044 217185.00097351
+ 640187.13632455 217161.66117706
+ 1     50        
+L  2 1
+ 640187.13632455 217161.66117706
+ 640166.20300793 217137.70081734
+ 1     50        
+L  5 1
+ 640299.81120399 217188.22025578
+ 640320.73653874 217200.29256429
+ 640350.51489974 217230.07092529
+ 640363.39202882 217251.80108061
+ 640372.24505506 217277.55533876
+ 1     52        
+L  3 1
+ 640187.13632455 217161.66117706
+ 640228.18217349 217177.75758841
+ 640299.81120399 217188.22025578
+ 1     51        
+L  3 1
+ 640299.81120399 217188.22025578
+ 640352.12454087 217181.78169124
+ 640370.63541392 217182.58651181
+ 1     51        
+L  4 1
+ 640014.90472313 217113.37194301
+ 640080.90000965 217109.34784018
+ 640106.65426781 217106.93337847
+ 640126.774782 217098.8851728
+ 1     53        
+L  3 1
+ 640016.51436426 217180.97687067
+ 640075.26626568 217143.15030401
+ 640126.774782 217098.8851728
+ 1     48        
+L  4 1
+ 640496.992243 217076.35019691
+ 640466.40906144 217078.76465861
+ 640433.41141818 217079.56947918
+ 640430.56728114 217079.88549441
+ 1     55        
+L  2 1
+ 640430.56728114 217079.88549441
+ 640524.79032019 217124.51746028
+ 1     32        
+L  2 1
+ 639923.75454847 217316.53019876
+ 639766.66255648 217232.77558234
+ 1     57        
+L  2 1
+ 639766.66255648 217232.77558234
+ 639753.78382216 217163.94942052
+ 1     30        
+L  2 1
+ 639696.17129704 217379.58537484
+ 639775.58233648 217280.4444143
+ 1     56        
+L  2 1
+ 639791.79566719 217367.09123033
+ 639775.58233648 217280.4444143
+ 1     30        
+L  2 1
+ 639775.58233648 217280.4444143
+ 639766.66255648 217232.77558234
+ 1     30        
+L  6 1
+ 640286.93407491 217099.68999337
+ 640266.81356073 217036.10916854
+ 640274.8617664 216995.0633196
+ 640272.4473047 216974.94280542
+ 640270.032843 216953.2126501
+ 640270.99789385 216947.66888143
+ 1     54        
+L  3 1
+ 640166.20300793 216826.57359053
+ 640247.93982175 216924.13043283
+ 640270.99789385 216947.66888143
+ 1     32        
+L  3 1
+ 640270.99789385 216947.66888143
+ 640374.50004961 217053.32733211
+ 640430.56728114 217079.88549441
+ 1     32        
+L  2 1
+ 643330.84774108 216725.01860524
+ 643202.29377332 216520.61063111
+ 1     20        
+L  3 1
+ 642993.86148565 216692.5380023
+ 643127.84397275 216591.03611814
+ 643202.29377332 216520.61063111
+ 1     19        
+L  4 1
+ 643202.29377332 216520.61063111
+ 643278.06676132 216448.93348031
+ 643363.32834402 216314.95099321
+ 643347.08804255 216156.60805391
+ 1     19        
+L  5 1
+ 639957.90596625 216148.94903721
+ 640037.00610866 216183.22576559
+ 640129.28960814 216188.49910842
+ 640195.20639348 216188.49910842
+ 640207.3392106 216189.4820258
+ 1     37        
+L  3 1
+ 640370.51159953 216144.2928286
+ 640255.84983599 216164.76906569
+ 640207.3392106 216189.4820258
+ 1     33        
+L  6 1
+ 640207.3392106 216189.4820258
+ 640206.384856 216189.96820644
+ 640205.09925849 216190.62313348
+ 640116.10625107 216235.95919386
+ 639968.4526519 216301.8759792
+ 639768.06562446 216349.33606465
+ 1     33        
+L  5 1
+ 640409.61787735 216585.33800325
+ 640466.78354909 216657.82662005
+ 640532.70033443 216718.47006257
+ 640603.8904626 216752.74679095
+ 640656.62389088 216781.7501765
+ 1     44        
+L  4 1
+ 640409.61787735 216585.33800325
+ 640445.69017778 216589.2731633
+ 640540.61034867 216583.99982047
+ 640627.62050533 216581.36314906
+ 1     43        
+L  3 1
+ 640221.51282885 216510.13508436
+ 640300.67325003 216573.45313481
+ 640409.61787735 216585.33800325
+ 1     43        
+L  4 1
+ 640406.14010658 216781.7501765
+ 640276.9432073 216655.18994864
+ 640224.20977903 216570.8164634
+ 640221.51282885 216510.13508436
+ 1     42        
+L  3 1
+ 640221.51282885 216510.13508436
+ 640218.9364362 216452.16624978
+ 640214.27389593 216423.87608767
+ 1     42        
+L  3 1
+ 640126.774782 217098.8851728
+ 640148.50493732 217067.49717067
+ 640166.20300793 217045.44843503
+ 1     48        
+L  2 1
+ 640166.20300793 216826.57359053
+ 640166.20300793 217045.44843503
+ 1     31        
+L  2 1
+ 640166.20300793 217045.44843503
+ 640166.20300793 217137.70081734
+ 1     31        

Added: grass-addons/grass7/vector/v.stream.order/testsuite/data/stream_network_outlets.txt
===================================================================
--- grass-addons/grass7/vector/v.stream.order/testsuite/data/stream_network_outlets.txt	                        (rev 0)
+++ grass-addons/grass7/vector/v.stream.order/testsuite/data/stream_network_outlets.txt	2016-04-10 12:53:24 UTC (rev 68243)
@@ -0,0 +1,29 @@
+ORGANIZATION: 
+DIGIT DATE:   
+DIGIT NAME:   soeren
+MAP NAME:     
+MAP DATE:     Mon Nov 23 09:41:14 2015
+MAP SCALE:    1
+OTHER INFO:   
+ZONE:         0
+MAP THRESH:   0.000000
+VERTI:
+P  1 1
+ 641762.6178191 215109.77637672
+ 1     1         
+P  1 1
+ 642632.27087271 215183.86995156
+ 1     2         
+P  1 1
+ 643421.88123234 215105.44974461
+ 1     3         
+
+P  1 1
+ 641762.6178191 215109.77637672
+ 1     4
+P  1 1
+ 642632.27087271 215183.86995156
+ 1     5
+P  1 1
+ 643421.88123234 215105.44974461
+ 1     6

Added: grass-addons/grass7/vector/v.stream.order/testsuite/generate_manpage_images.sh
===================================================================
--- grass-addons/grass7/vector/v.stream.order/testsuite/generate_manpage_images.sh	                        (rev 0)
+++ grass-addons/grass7/vector/v.stream.order/testsuite/generate_manpage_images.sh	2016-04-10 12:53:24 UTC (rev 68243)
@@ -0,0 +1,68 @@
+#!/bin/bash
+# Author: IGB-Berlin,Johannes Radinger; Implementation: Soeren Gebbert"
+# This tool was developed as part of the BiodivERsA-net project 'FISHCON'
+# and has been funded by the German Federal Ministry for Education and
+# Research (grant number 01LC1205). 
+
+# Generate the map and images for the HTML documentation
+export GRASS_OVERWRITE=1
+
+# Import the stream network and the outlet points
+v.in.ascii input=data/stream_network.txt output=stream_network \
+    format=standard
+v.in.ascii input=data/stream_network_outlets.txt output=stream_network_outlets \
+    format=standard
+
+# Compute the different stream orders
+v.stream.order input=stream_network points=stream_network_outlets \
+    output=stream_network_order threshold=25 \
+    order=strahler,shreve,drwal,scheidegger
+
+# Set the correct region to visualize the 3 stream network
+n=216770
+s=215080
+w=642660
+e=644040
+g.region s=${s} n=${n} e=${e} w=${w} -p
+
+export GRASS_RENDER_WIDTH=400
+export GRASS_RENDER_HIGHT=800
+d.mon start=ps output=map.ps
+d.erase
+d.vect map=stream_network display=shape,dir \
+    width=3 size=10 label_size=20
+
+convert map.ps stream_network.pdf
+convert stream_network.pdf stream_network.png
+
+d.erase
+d.vect map=stream_network_order display=shape,dir \
+    width=3 width_column=strahler width_scale=3 size=15 \
+    attribute_column=strahler label_size=35 where="network = 3"
+
+convert map.ps stream_network_order_strahler.pdf
+convert stream_network_order_strahler.pdf stream_network_order_strahler.png
+
+d.erase
+d.vect map=stream_network_order display=shape,dir \
+    width=3 width_column=shreve width_scale=3 size=15 \
+    attribute_column=shreve label_size=35 where="network = 3"
+
+convert map.ps stream_network_order_shreve.pdf
+convert stream_network_order_shreve.pdf stream_network_order_shreve.png
+
+d.erase
+d.vect map=stream_network_order display=shape,dir \
+    width=3 width_column=drwal width_scale=3 size=15 \
+    attribute_column=drwal label_size=35 where="network = 3"
+
+convert map.ps stream_network_order_drwal.pdf
+convert stream_network_order_drwal.pdf stream_network_order_drwal.png
+
+d.erase
+d.vect map=stream_network_order display=shape,dir \
+    width=3 width_column=scheidegger width_scale=3 size=15 \
+    attribute_column=scheidegger label_size=35 where="network = 3"
+
+convert map.ps stream_network_order_scheidegger.pdf
+convert stream_network_order_scheidegger.pdf stream_network_order_scheidegger.png

Added: grass-addons/grass7/vector/v.stream.order/testsuite/generate_stream_outflow_points.sh
===================================================================
--- grass-addons/grass7/vector/v.stream.order/testsuite/generate_stream_outflow_points.sh	                        (rev 0)
+++ grass-addons/grass7/vector/v.stream.order/testsuite/generate_stream_outflow_points.sh	2016-04-10 12:53:24 UTC (rev 68243)
@@ -0,0 +1,20 @@
+#!/bin/bash
+# This script creates the water outlet points
+# for different stream networks in the "streams at PERMANENT"
+# vector map layer in the nc location
+# Author: IGB-Berlin,Johannes Radinger; Implementation: Soeren Gebbert"
+# This tool was developed as part of the BiodivERsA-net project 'FISHCON'
+# and has been funded by the German Federal Ministry for Education and
+# Research (grant number 01LC1205). 
+
+cat > points.csv << EOF
+640781.56098|214897.033189
+642228.347134|214979.370612
+638470.926725|214984.99142
+645247.580918|223346.644849
+638470.926725|214984.99142
+645247.580918|223346.644849
+EOF
+
+v.in.ascii output=stream_outflow input=points.csv x=1 y=2
+

Added: grass-addons/grass7/vector/v.stream.order/testsuite/test_stream_order.py
===================================================================
--- grass-addons/grass7/vector/v.stream.order/testsuite/test_stream_order.py	                        (rev 0)
+++ grass-addons/grass7/vector/v.stream.order/testsuite/test_stream_order.py	2016-04-10 12:53:24 UTC (rev 68243)
@@ -0,0 +1,188 @@
+"""Test v.stream.order
+
+ at author
+IGB-Berlin,Johannes Radinger; Implementation: Soeren Gebbert"
+This tool was developed as part of the BiodivERsA-net project 'FISHCON'
+and has been funded by the German Federal Ministry for Education and
+Research (grant number 01LC1205). 
+
+(C) 2014 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.
+
+"""
+
+from grass.gunittest.case import TestCase
+from grass.pygrass.vector import VectorTopo
+
+
+class TestStreamOrder(TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        cls.runModule("v.in.ascii", input="data/stream_network.txt",
+                      output="stream_network", format="standard",
+                      overwrite=True)
+
+        cls.runModule("v.in.ascii", input="data/stream_network_outlets.txt",
+                      output="stream_network_outlets", format="standard")
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.runModule("g.remove",  flags="f",  type="vector",  
+                      name="stream_network,stream_network_outlets")
+
+    def tearDown(self):
+        pass
+        self.runModule("g.remove",  flags="f",  type="vector",  
+                       pattern="stream_network_order_test_*")
+
+    def test_strahler(self):
+        self.assertModule("v.stream.order", input="stream_network",
+                          points="stream_network_outlets",
+                          output="stream_network_order_test_strahler",
+                          threshold=25,
+                          order=["strahler"],
+                          overwrite=True,  verbose=True)
+
+        # Check the strahler value
+        v = VectorTopo(name="stream_network_order_test_strahler",
+                       mapset="")
+        v.open(mode="r")
+
+        self.assertTrue(v.exist(), True)
+        self.assertEqual(v.num_primitive_of("line"), 101)
+        # feature 4
+        self.assertEqual(v.read(4).attrs.cat, 41)
+        self.assertEqual(v.read(4).attrs["outlet_cat"], 1)
+        self.assertEqual(v.read(4).attrs["network"], 1)
+        self.assertEqual(v.read(4).attrs["reversed"], 0)
+        self.assertEqual(v.read(4).attrs["strahler"], 4)
+        
+        v.close()
+
+    def test_all(self):
+        self.assertModule("v.stream.order", input="stream_network",
+                          points="stream_network_outlets",
+                          output="stream_network_order_test_all",
+                          threshold=25,
+                          order=["strahler", "shreve", "drwal", "scheidegger"],
+                          overwrite=True,  verbose=True)
+
+        # Check all values
+        v = VectorTopo(name="stream_network_order_test_all",
+                       mapset="")
+        v.open(mode="r")
+        self.assertTrue(v.exist(), True)
+        self.assertEqual(v.num_primitive_of("line"), 101)
+        # feature 4
+        self.assertEqual(v.read(4).attrs.cat, 41)
+        self.assertEqual(v.read(4).attrs["outlet_cat"], 1)
+        self.assertEqual(v.read(4).attrs["network"], 1)
+        self.assertEqual(v.read(4).attrs["reversed"], 0)
+        self.assertEqual(v.read(4).attrs["strahler"], 4)
+        self.assertEqual(v.read(4).attrs["shreve"], 32)
+        self.assertEqual(v.read(4).attrs["drwal"], 6)
+        self.assertEqual(v.read(4).attrs["scheidegger"], 64)
+        v.close()
+
+        # Check for column copy
+        self.assertModule("v.stream.order",
+                          input="stream_network_order_test_all",
+                          points="stream_network_outlets",
+                          output="stream_network_order_test_all_2",
+                          threshold=25,
+                          order=["strahler", "shreve", "drwal", "scheidegger"],
+                          columns=["strahler", "shreve", "drwal", "scheidegger"],
+                          overwrite=True,  verbose=True)
+
+        # Check all values and their copies
+        v = VectorTopo(name="stream_network_order_test_all_2",
+                       mapset="")
+        v.open(mode="r")
+        self.assertTrue(v.exist(), True)
+        self.assertEqual(v.num_primitive_of("line"), 101)
+        # feature 4
+        self.assertEqual(v.read(4).attrs.cat, 4)
+        self.assertEqual(v.read(4).attrs["outlet_cat"], 1)
+        self.assertEqual(v.read(4).attrs["network"], 1)
+        self.assertEqual(v.read(4).attrs["reversed"], 0)
+        self.assertEqual(v.read(4).attrs["strahler"], 4)
+        self.assertEqual(v.read(4).attrs["shreve"], 32)
+        self.assertEqual(v.read(4).attrs["drwal"], 6)
+        self.assertEqual(v.read(4).attrs["scheidegger"], 64)
+        self.assertEqual(v.read(4).attrs["strahler_1"], 4)
+        self.assertEqual(v.read(4).attrs["shreve_1"], 32)
+        self.assertEqual(v.read(4).attrs["drwal_1"], 6)
+        self.assertEqual(v.read(4).attrs["scheidegger_1"], 64)
+        # feature 7
+        self.assertEqual(v.read(7).attrs.cat, 7)
+        self.assertEqual(v.read(7).attrs["outlet_cat"], 1)
+        self.assertEqual(v.read(7).attrs["network"], 1)
+        self.assertEqual(v.read(7).attrs["reversed"], 0)
+        self.assertEqual(v.read(7).attrs["strahler"], 2)
+        self.assertEqual(v.read(7).attrs["strahler_1"], 2)
+        self.assertEqual(v.read(7).attrs["shreve"], 4)
+        self.assertEqual(v.read(7).attrs["drwal"], 3)
+        self.assertEqual(v.read(7).attrs["scheidegger"], 8)
+        v.close()
+
+
+class TestStreamOrderFails(TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        cls.runModule("v.in.ascii", input="data/stream_network.txt",
+                      output="stream_network", format="standard",
+                      overwrite=True)
+
+        cls.runModule("v.in.ascii", input="data/stream_network_outlets.txt",
+                      output="stream_network_outlets", format="standard")
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.runModule("g.remove",  flags="f",  type="vector",  
+                      name="stream_network,stream_network_outlets")
+
+    def test_error_handling_1(self):
+        # No input points
+        self.assertModuleFail("v.stream.order", input="stream_network",
+                              output="stream_network_order", threshold=25,
+                              order=["strahler", "shreve", "drwal", "scheidegger"])
+                              
+    def test_error_handling_2(self):
+        # No input network
+        self.assertModuleFail("v.stream.order",
+                              points="stream_network_outlets",
+                              output="stream_network_order", threshold=25,
+                              order=["strahler", "shreve", "drwal", "scheidegger"])
+                              
+    def test_error_handling_3(self):
+        # No output
+        self.assertModuleFail("v.stream.order", input="stream_network",
+                              points="stream_network_outlets",
+                              threshold=25,
+                              order=["strahler", "shreve", "drwal", "scheidegger"],
+                              overwrite=True,  verbose=True)
+                              
+    def test_error_handling_4(self):
+        # Recursion limit is below 1000
+        self.assertModuleFail("v.stream.order", input="stream_network",
+                              points="stream_network_outlets",
+                              output="stream_network_order", threshold=25,
+                              order=["strahler", "shreve", "drwal", "scheidegger"],
+                              recursionlimit=0,
+                              overwrite=True,  verbose=True)
+                              
+    def test_error_handling_5(self):
+        # Horton order is not implemented
+        self.assertModuleFail("v.stream.order", input="stream_network",
+                              points="stream_network_outlets",
+                              output="stream_network_order", threshold=25,
+                              order=["horton"],
+                              overwrite=True,  verbose=True)
+
+if __name__ == '__main__':
+    from grass.gunittest.main import test
+    test()

Added: grass-addons/grass7/vector/v.stream.order/v.stream.order.html
===================================================================
--- grass-addons/grass7/vector/v.stream.order/v.stream.order.html	                        (rev 0)
+++ grass-addons/grass7/vector/v.stream.order/v.stream.order.html	2016-04-10 12:53:24 UTC (rev 68243)
@@ -0,0 +1,198 @@
+<h2>DESCRIPTION</h2>
+
+The module <i>v.stream.order </i> is designed to compute different
+stream order approaches based on a stream network vector map and a water
+outlet vector point map. It requires two inputs:
+<ol>
+    <li>A vector line map with one or several independent stream networks</li>
+    <li>A vector point map that defines the water outlet points in the stream network</li>
+</ol>
+A single output vector map containing all detected networks and all specified orders
+is generated as output.
+
+<p>
+    The direction of the stream flow will be adjusted in outlet direction and stored in the
+    output vector map.<br><br>
+
+    To determine the outlet stream network segment, a nearest neighbor search is performed.
+    The threshold of the search can be adjusted with the <i>threshold</i> option.
+    It is required to specify the threshold as floating point value
+    that is interpreted using the locations projection unit. <br><br>
+
+    It is required that the vector line direction of the network segment that was found
+    at the outlet point, is directed to the outlet point. Since, the depth-first search
+    network traversing will be performed in upstream direction. Stream networks in
+    downstream direction will be detected. However, the stream order will not be computed.
+    The stream order table entries will be empty. <br><br>
+
+    The output vector map contains a column for each specified order algorithm,
+    the network id, the outlet category of the vector point input map
+    and the column <i>reversed</i>. The column reversed indicates if the
+    stream network segment was reversed in direction to point to
+    the water outlet point (0 - not reversed, 1 - reversed).<br><br>
+
+    In addition all columns from the stream network input map
+    are copied to the output vector map. The input vector map columns that
+    should be copied will be automagically renamed in the output vector map, 
+    if the column names are conflicting with each other. Use the <i>columns</i>
+    parameter to specifiy a subset of columns that should be copied. 
+    The keyword <i>all</i> is used to copy all columns to the output vector map
+    that are found in the input vector map (default). 
+
+</p>
+
+<h2>Note</h2>
+<p>
+      Be aware that the stream network map must be topological correct.
+      Each independent stream network must be properly connected.
+      The implemented stream order algorithms rely on topological relations between lines and nodes
+      and are not designed to handle loops and channels in the stream networks correctly.<br><br>
+      
+      The network traversing method, that is used to compute the stream order numbers,
+      is recursively implemented. In case of large stream networks, or networks
+      with many loops, the maximum recursion depth of Python may be reached.
+      The module will stop then with an <i>maximum recursion depth exceeded</i> exception.
+      This parameter can be adjusted with the <i>recursionlimit</i> option. The default in Python is 1000.
+      The default in v.stream.order is 10000.
+</p>
+
+<h2>Supported stream order algorithms</h2>
+
+The following algorithm examples are based on this stream network.
+Be aware of the wrong stream directions that will be adjusted by v.stream.order.<br>
+<img src="stream_network.png" border="0" height="240" width="200"><br>
+
+<h3>Strahler's stream order</h3>
+
+<img src="stream_network_order_strahler.png" border="0" height="240" width="200"><br>
+
+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. 
+<p>
+    <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.
+</p>
+<p>
+    The disadvantage of that methods is the lack of distinguishing a main
+    channel which may interfere with the analytical process in highly elongated
+    catchments. It is not able to handle loops in the ordered graph correctly.
+</p>
+
+<p>
+<h3>Shreve's stream magnitude</h3>
+
+<img src="stream_network_order_shreve.png" border="0" height="240" width="200"><br>
+
+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. 
+
+<h3>Scheidegger's stream magnitude</h3>
+
+<img src="stream_network_order_scheidegger.png" border="0" height="240" width="200"><br>
+
+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.
+
+<h3>Drwal's stream hierarchy </h3>
+
+<img src="stream_network_order_drwal.png" border="0" height="240" width="200"><br>
+
+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 higher 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 idealized binary tree. Drwal's order is computed based on
+Shreve's magnitude with the formula: <b>floor(log(shreve,2))+1</b>.
+<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
+    disadvantage is that it minimize bifurcation ratio of the network.
+</p>
+
+<h2>Examples</h2>
+
+<h3>Stream order computation based on North Carolina location</h3>
+
+<div class="code"><pre>
+# We need to generate 4 outlet points that will lead to
+# 4 stream networks and therefore 4 output vector maps
+cat > points.csv << EOF
+640781.56098|214897.033189
+642228.347134|214979.370612
+638470.926725|214984.99142
+645247.580918|223346.644849
+EOF
+
+v.in.ascii output=streams_outlets input=points.csv x=1 y=2
+    
+v.stream.order input=streams at PERMANENT points=streams_outlets \
+    output=streams_order threshold=25 order=strahler,shreve
+
+v.info streams_order
+v.db.select streams_order | less
+
+</pre></div>
+
+<h3>Stream order computation based on v.stream.order testsuite data</h3>
+
+<div class="code"><pre>
+v.stream.order input=stream_network points=stream_network_outlets \
+    output=stream_network_order threshold=25 \
+    order=strahler,shreve,drwal,scheidegger
+
+v.info stream_network_order
+v.db.select stream_network_order | less
+</pre></div>
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.stream.order.html">r.stream.order</a>
+</em>
+
+<h2>REFERENCES</h2>
+<a href="r.stream.order.html">r.stream.order</a><br>
+<a href="https://en.wikipedia.org/wiki/Depth-first_search">Depth first search at Wikipedia</a><br>
+<a href="https://en.wikipedia.org/wiki/Strahler_number">Strahler number at Wikipedia</a><br>
+
+<h2>AUTHOR</h2>
+<p>IGB-Berlin,Johannes Radinger; Implementation: Soeren Gebbert</p>
+<p>
+    This tool was developed as part of the BiodivERsA-net project 'FISHCON'
+    and has been funded by the German Federal Ministry for Education and
+    Research (grant number 01LC1205).
+</p>
+<p>Documentation of the implemented algorithms are in most parts copied from 
+   r.stream.order implemented by: Jarek  Jasiewicz and Markus Metz</p>
+
+<p><i>Last changed: $Date: 2013-03-27 10:11:17 +0100 (Mi, 27. Mär 2013) $</i>
+

Added: grass-addons/grass7/vector/v.stream.order/v.stream.order.py
===================================================================
--- grass-addons/grass7/vector/v.stream.order/v.stream.order.py	                        (rev 0)
+++ grass-addons/grass7/vector/v.stream.order/v.stream.order.py	2016-04-10 12:53:24 UTC (rev 68243)
@@ -0,0 +1,580 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+############################################################################
+#
+# MODULE:       v.stream.order
+# AUTHOR(S):    IGB-Berlin,Johannes Radinger; Implementation: Soeren Gebbert"
+#
+#               This tool was developed as part of the BiodivERsA-net project 'FISHCON'
+#               and has been funded by the German Federal Ministry for Education and
+#               Research (grant number 01LC1205). 
+#
+# PURPOSE:      Compute the stream order of stream networks stored in
+#               a vector map at specific outlet vector points
+# COPYRIGHT:    (C) 2015 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: Compute the stream order of stream networks stored in a vector map at specific outlet vector points
+#% keyword: vector
+#%end
+#%option G_OPT_V_INPUT
+#% description: Name of the stream networks vector map
+#%end
+#%option G_OPT_V_INPUT
+#% key: points
+#% label: Name of the input vector point map
+#% description: Name of the points vector map that defines the water outlets of the stream networks
+#%end
+#%option G_OPT_V_OUTPUT
+#% label: Name of the vector output map
+#% description: The name for the stream order vector output map
+#%end
+#%option
+#% key: threshold
+#% type: double
+#% description: threshold in projection units used to search for outflow points at the stream network
+#% required : no
+#% answer: 25
+#% multiple: no
+#%end
+#%option
+#% key: order
+#% type: string
+#% description: The stream order to compute
+#% required : no
+#% answer: strahler,shreve
+#% options: strahler,shreve,scheidegger,drwal
+#% multiple: yes
+#%end
+#%option
+#% key: columns
+#% type: string
+#% description: The columns that should be copied from the input stream vector map. By default all will be copied.
+#% answer: all
+#% required : no
+#% multiple: yes
+#%end
+#%option
+#% key: recursionlimit
+#% type: integer
+#% description:The Python recursion limit that should be used (Python default is 1000)
+#% required : no
+#% answer: 10000
+#% multiple: no
+#%end
+
+import os
+import sys
+from grass.script import core as grass
+from grass.pygrass.vector import VectorTopo
+import math
+
+ORDER_STRAHLER = 1
+ORDER_SHREVE = 2
+ORDER_SCHEIDEGGER = 3
+ORDER_DRWAL = 4
+ORDER_HORTON = 5
+
+ORDER_DICT = {ORDER_STRAHLER: "strahler",
+              ORDER_SHREVE: "shreve",
+              ORDER_SCHEIDEGGER: "scheidegger",
+              ORDER_DRWAL: "drwal",
+              ORDER_HORTON: "horton"}
+
+
+class GraphEdge(object):
+    """
+    This class defines a single edge of the stream network graph
+    """
+
+    def __init__(self, id_, id_pol, start, end,
+                 start_edges, end_edges,
+                 reverse=False):
+        self.id = id_  # Line id
+        self.id_pol = id_pol  # Polarity of line positive integer or negative integer
+        self.start = start  # Start Node id
+        self.end = end  # End Node id
+        self.start_edges = start_edges  # A list of edge ids at the start node
+        self.end_edges = end_edges  # A list of edge ids at the end node
+        self.reverse = reverse  # If the edge should be reversed
+        self.stream_order = {ORDER_STRAHLER: 0,
+                             ORDER_SHREVE: 0,
+                             ORDER_SCHEIDEGGER: 0,
+                             ORDER_DRWAL: 0}  # stream_order for each algorithm
+
+    def __str__(self):
+        return "Line id: %i (%i) start node: %i " \
+               "end node: %i num start edges %i " \
+               "num end edges %i   reverse: %s stream_order: %s" % (self.id, self.id_pol,
+                                                                    self.start, self.end,
+                                                                    len(self.start_edges),
+                                                                    len(self.end_edges),
+                                                                    self.reverse, str(self.stream_order))
+
+
+class GraphNode(object):
+    """
+    This class defines a single node of the node network graph
+    """
+
+    def __init__(self, id_, edge_ids):
+        self.id = id_  # Node id
+        self.edge_ids = edge_ids  # Line ids
+
+    def __str__(self):
+        return "Node id: %i line ids: %s" % (self.id, self.edge_ids)
+
+
+def traverse_graph_create_stream_order(start_id,
+                                       edges,
+                                       checked_edges,
+                                       reversed_edges,
+                                       order_types=[ORDER_STRAHLER,
+                                                    ORDER_SHREVE]):
+    """
+    Traverse the graph, reverse lines that are not in
+    the outflow direction and compute the required orders
+    
+    :param start_id: The id of the edge to start the traversing from
+    :param edges: A dictionary of edge objects
+    :param checked_edges: A list with edge ids that have been checked already
+    :param reversed_edges: A list of edges that have been checked for
+                           reversion and corrected if necessary
+    :param order_types: The type of the ordering scheme as a list of ints
+                      * ORDER_STRAHLER = 1
+                      * ORDER_SHREVE = 2
+                      * ORDER_SCHEIDEGGER = 3
+                      * ORDER_DRWAL = 4
+                      * ORDER_HORTON = 5 -> Not correct implemented
+                      
+    :return:
+    """
+    current_edge = edges[start_id]
+
+    # Check for direction reversion
+    for edge_id in current_edge.start_edges:
+        if edge_id not in reversed_edges:
+            reversed_edges.append(edge_id)
+            edge = edges[edge_id]
+
+            # Reverse the edge if it is not in the outflow direction
+            if current_edge.start != edge.end:
+                start = edge.start
+                start_edges = edge.start_edges
+                edge.start = edge.end
+                edge.start_edges = edge.end_edges
+                edge.end = start
+                edge.end_edges = start_edges
+                edge.reverse = True
+
+    # Set the stream_order to one, if the edge is a leaf and return
+    if len(current_edge.start_edges) == 0:
+        for order in current_edge.stream_order:
+            current_edge.stream_order[order] = 1
+        return
+
+    stream_orders = {ORDER_STRAHLER: [],
+                     ORDER_SHREVE: [],
+                     ORDER_SCHEIDEGGER: [],
+                     ORDER_HORTON: [],
+                     ORDER_DRWAL: []}
+
+    # Traverse the graph if its not a leaf
+    for edge_id in current_edge.start_edges:
+        if edge_id not in checked_edges:
+            checked_edges.append(edge_id)
+            traverse_graph_create_stream_order(edge_id,
+                                               edges,
+                                               checked_edges,
+                                               reversed_edges,
+                                               order_types)
+
+        for order in order_types:
+            stream_orders[order].append(edges[edge_id].stream_order[order])
+
+    # Compute the stream orders
+    if ORDER_STRAHLER in order_types:
+        maximum = max(stream_orders[ORDER_STRAHLER])
+        if stream_orders[ORDER_STRAHLER].count(maximum) > 1:
+            current_edge.stream_order[ORDER_STRAHLER] = maximum + 1
+        else:
+            current_edge.stream_order[ORDER_STRAHLER] = maximum
+    if ORDER_SHREVE in order_types:
+        current_edge.stream_order[ORDER_SHREVE] = sum(stream_orders[ORDER_SHREVE])
+    if ORDER_SCHEIDEGGER in order_types:
+        current_edge.stream_order[ORDER_SCHEIDEGGER] = sum(stream_orders[ORDER_SCHEIDEGGER])
+    if ORDER_DRWAL in order_types:
+        current_edge.stream_order[ORDER_DRWAL] = sum(stream_orders[ORDER_DRWAL])
+    # Horton is wrong implemented
+    if ORDER_HORTON in order_types:
+        maximum = max(stream_orders[ORDER_HORTON])
+        current_edge.stream_order[ORDER_HORTON] = maximum + 1
+
+
+def traverse_network_create_graph(vector, start_node, graph_nodes, graph_edges):
+    """
+    Traverse a stream network vector map layer with depth-first search
+    and create a graphs structures for nodes and edges
+
+    :param vector: The opened vector input file
+    :param start_node: The start node object
+    :param graph_nodes: A dictionary of discovered nodes
+    :param graph_edges: A dictionary of Edge objects
+    :return:
+    """
+
+    # Count line ids
+    edge_ids = start_node.ilines()
+
+    # For each line at that node
+    for line_id in edge_ids:
+
+        line_id_abs = abs(line_id)
+        line = vector.read(line_id_abs)
+        nodes = line.nodes()
+
+        # If the line id is not in the edge list, create a new entry
+        if line_id_abs not in graph_edges:
+            start_edges = [abs(lid) for lid in nodes[0].ilines()]
+            end_edges = [abs(lid) for lid in nodes[1].ilines()]
+
+            start_edges.remove(line_id_abs)
+            end_edges.remove(line_id_abs)
+
+            e = GraphEdge(line_id_abs,
+                          line_id,
+                          nodes[0].id,
+                          nodes[1].id,
+                          start_edges,
+                          end_edges,
+                          False)
+            graph_edges[line_id_abs] = e
+
+        # For start and end node
+        for node in nodes:
+            # If the node was not yet discovered, put it
+            # into the node dict and call traverse
+            if node.id not in graph_nodes:
+                graph_nodes[node.id] = GraphNode(node.id,
+                                                 [lid for lid in node.ilines()])
+                # Recursive call
+                traverse_network_create_graph(vector, node,
+                                              graph_nodes,
+                                              graph_edges)
+
+
+def graph_to_vector(name, mapset, graphs,
+                    output, order_types,
+                    outlet_cats, copy_columns):
+    """
+    Write the Graph as vector map. Attach the network id,
+    the streams orders, the reverse falg, the original
+    category and copy columns from the source stream network
+    vector map if required.
+
+    :param name: Name of the input stream vector map
+    :param mapset: Mapset name of the input stream vector map
+    :param graphs: The list of computed graphs
+    :param output: The name of the output vector map
+    :param order_types: The order algorithms
+    :param outlet_cats: Categories of the outlet points
+    :param copy_columns: The column names to be copied from the original input map
+    :return:
+    """
+    streams = VectorTopo(name=name, mapset=mapset)
+    streams.open("r")
+
+    # Specifiy all columns that should be created
+    cols = [("cat", "INTEGER PRIMARY KEY"),
+            ("outlet_cat", "INTEGER"),
+            ("network", "INTEGER"),
+            ("reversed", "INTEGER")]
+
+    for order in order_types:
+        cols.append((ORDER_DICT[order], "INTEGER"))
+
+    # Add the columns of the table from the input map
+    if copy_columns:
+        for entry in copy_columns:
+            cols.append((entry[1], entry[2]))
+
+    out_streams = VectorTopo(output)
+    grass.message(_("Writing vector map <%s>" % output))
+    out_streams.open("w", tab_cols=cols)
+
+    count = 0
+    for graph in graphs:
+        outlet_cat = outlet_cats[count]
+        count += 1
+
+        grass.message(_("Writing network %i from %i with "
+                        "outlet category %i" % (count, len(graphs), outlet_cat)))
+
+        # Write each edge as line
+        for edge_id in graph:
+            edge = graph[edge_id]
+
+            line = streams.read(edge_id)
+            # Reverse the line if required
+            if edge.reverse is True:
+                line.reverse()
+
+            # Orders derived from shreve algorithm
+            if ORDER_SCHEIDEGGER in order_types:
+                edge.stream_order[ORDER_SCHEIDEGGER] *= 2
+            if ORDER_DRWAL in order_types:
+                if edge.stream_order[ORDER_DRWAL] != 0:
+                    edge.stream_order[ORDER_DRWAL] = \
+                        int(math.log(edge.stream_order[ORDER_DRWAL], 2) + 1)
+
+            # Create attributes
+            attrs = []
+            # Append the outlet point category
+            attrs.append(outlet_cat)
+            # Append the network id
+            attrs.append(count)
+            # The reverse flag
+            attrs.append(edge.reverse)
+            # Then the stream orders defined at the command line
+            for order in order_types:
+                val = int(edge.stream_order[order])
+                if val == 0:
+                    val = None
+                attrs.append(val)
+            # Copy attributes from original streams if the table exists
+            if copy_columns:
+                for entry in copy_columns:
+                    # First entry is the column index
+                    attrs.append(line.attrs.values()[entry[0]])
+
+            # Write the feature
+            out_streams.write(line, cat=edge_id, attrs=attrs)
+
+    # Commit the database entries
+    out_streams.table.conn.commit()
+    # Close the input and output map
+    out_streams.close()
+    streams.close()
+
+
+def detect_compute_networks(vname, vmapset, pname, pmapset,
+                            output, order, columns, threshold):
+    """
+    Detect the start edges and nodes, compute the stream networks
+    and stream orders, reverse edges and write everything into the
+    output vector map.
+
+    :param vname: Name of the input stream vector map
+    :param vmapset: Mapset name of the input stream vector map
+    :param pname: Name of the input outlet points vector map
+    :param pmapset: Mapset name of the input outlet points vector map
+    :param output: Name of the output stream vector map
+    :param order: Comma separated list of order algorithms
+    :param columns: Comma separated list of column names that should be copied to the output
+    :param threshold: The point search threshold to find start edges and nodes
+    :return:
+    """
+
+    v = VectorTopo(name=vname, mapset=vmapset)
+    p = VectorTopo(name=pname, mapset=pmapset)
+
+    v.open(mode="r")
+    p.open(mode="r")
+
+    copy_columns = None
+
+    # Check for copy columns only if the input vector map 
+    # has an attribute table
+    if v.table and columns:
+
+        # These are the column names that are newly created
+        # and it must be checked if their names
+        # are exist in the input map column names
+        # that should be copied
+        # Synchronize these names with the graph_to_vector() function
+        new_column_names = order.split(",")
+        new_column_names.append("cat")
+        new_column_names.append("outlet_cat")
+        new_column_names.append("network")
+        new_column_names.append("reversed")
+        # Add the order colum names
+        new_column_names.extend(order)
+
+        # Check if all columns should be copied
+        if columns.lower() == "all":
+            columns = ",".join(v.table.columns.names())
+
+        copy_columns = []
+        for column in columns.split(","):
+            # Copy only columns that exists
+            if column in v.table.columns.names():
+                col_index = v.table.columns.names().index(column)
+                col_type = v.table.columns.types()[col_index]
+                # Rename the column if it conflicts with the
+                # order column names in the output map
+                if column in new_column_names:
+
+                    # Create name suffix and make sure that the new column name
+                    # does not exists
+                    number = 1
+                    suffix = ""
+                    while True:
+                        suffix = "_%i" % number
+                        if column + suffix not in new_column_names and \
+                           column + suffix not in columns.split(","):
+                            break
+                        number += 1
+
+                    grass.warning(_("Column name conflict: Renaming column "
+                                    "<%(col)s> from input map into %(col)s%(ap)s "
+                                    "in output map" % {"col": column, "ap": suffix}))
+                    column += suffix
+                copy_columns.append((col_index, column, col_type))
+            else:
+                v.close()
+                p.close()
+                grass.fatal(_("Column %s is not in attribute table of <%s>" % (column, vname)))
+
+    # Detect closest edges and nodes to the outflow points
+    # But why nodes, arent edges sufficient?
+    #     They may be useful when detecting loops and channels
+    #     in further improvements of v.stream.order.
+    start_nodes = []
+    start_node_ids = []
+    start_edges = []
+    outlet_cats = []
+
+    for point in p:
+        p_coords = point.coords()
+
+        line = v.find_by_point.geo(point=point, maxdist=float(threshold),
+                                   type="line")
+
+        if line:
+            n1, n2 = line.nodes()
+
+            n1_coords = n1.coords()
+            n2_coords = n2.coords()
+
+            # Compute closest node to the outflow point
+            dist1 = math.sqrt((p_coords[0] - n1_coords[0]) ** 2 +
+                              (p_coords[1] - n1_coords[1]) ** 2)
+            dist2 = math.sqrt((p_coords[0] - n2_coords[0]) ** 2 +
+                              (p_coords[1] - n2_coords[1]) ** 2)
+
+            if dist1 < dist2:
+                closest_node = n1
+            else:
+                closest_node = n2
+
+            grass.verbose(_("Detect edge <%i> for outflow point %s" % (line.id,
+                                                                       point.to_wkt())))
+
+            # Ignore identical starting points to avoid
+            # redundant networks in the output
+            if closest_node.id not in start_node_ids:
+                start_nodes.append(closest_node)
+                start_node_ids.append(closest_node.id)
+
+            if line.id not in start_edges:
+                start_edges.append(line.id)
+                outlet_cats.append(point.cat)
+            else:
+                grass.warning(_("Ignoring duplicated start edge"))
+
+    p.close()
+
+    if len(start_edges) == 0:
+        v.close()
+        grass.fatal(_("Unable to find start edges"))
+
+    if len(start_nodes) == 0:
+        v.close()
+        grass.fatal(_("Unable to find start nodes"))
+
+    # We create a graph representation for further computations
+    graphs = []
+
+    # Traverse each network from the outflow node on
+    for node in start_nodes:
+        graph_nodes = {}
+        graph_edges = {}
+        graph_nodes[node.id] = GraphNode(node.id, [lid for lid in node.ilines()])
+        traverse_network_create_graph(v, node, graph_nodes, graph_edges)
+        # For now we only use the edges graph
+        graphs.append(graph_edges)
+
+    # Close the vector map, since we have our own graph representation
+    v.close()
+
+    # Set stream order types
+    order_types = []
+
+    if order.find("strahler") >= 0:
+        order_types.append(ORDER_STRAHLER)
+    if order.find("scheidegger") >= 0:
+        order_types.append(ORDER_SCHEIDEGGER)
+    if order.find("drwal") >= 0:
+        order_types.append(ORDER_DRWAL)
+    if order.find("horton") >= 0:
+        order_types.append(ORDER_HORTON)
+    if order.find("shreve") >= 0:
+        order_types.append(ORDER_SHREVE)
+
+    # Compute the stream orders
+    for i in xrange(len(start_edges)):
+        edge_id = start_edges[i]
+        checked_edges = []
+        reversed_edges = []
+        traverse_graph_create_stream_order(edge_id, graphs[i],
+                                           checked_edges,
+                                           reversed_edges,
+                                           order_types)
+
+    # Write the graphs as vector map
+    graph_to_vector(vname, vmapset, graphs,
+                    output, order_types,
+                    outlet_cats, copy_columns)
+
+
+def main():
+    input = options["input"]
+    points = options["points"]
+    output = options["output"]
+    order = options["order"]
+    threshold = options["threshold"]
+    columns = options["columns"]
+    recursionlimit = options["recursionlimit"]
+
+    # We are using a recursive tree traversing algorithm, that may exceed
+    # the 1000 recursion length for huge networks.
+    # The default is 10000 in the option section
+    if int(recursionlimit) < 1000:
+        grass.fatal(_("The Python recursion limit should be equal or larger than 1000"))
+
+    sys.setrecursionlimit(int(recursionlimit))
+
+    # Check map names for mapsets
+    vname = input
+    vmapset = ""
+    if "@" in input:
+        vname, vmapset = input.split("@")
+
+    pname = points
+    pmapset = ""
+    if "@" in points:
+        pname, pmapset = points.split("@")
+
+    detect_compute_networks(vname, vmapset, pname, pmapset, output, order,
+                            columns, threshold)
+
+
+if __name__ == "__main__":
+    options, flags = grass.parser()
+    main()



More information about the grass-commit mailing list