[GRASS-SVN] r67494 - in grass-addons/grass7/vector: . v.mapcalc

svn_grass at osgeo.org svn_grass at osgeo.org
Tue Jan 5 19:05:44 PST 2016


Author: wenzeslaus
Date: 2016-01-05 19:05:44 -0800 (Tue, 05 Jan 2016)
New Revision: 67494

Added:
   grass-addons/grass7/vector/v.mapcalc/
   grass-addons/grass7/vector/v.mapcalc/Makefile
   grass-addons/grass7/vector/v.mapcalc/v.mapcalc.html
   grass-addons/grass7/vector/v.mapcalc/v.mapcalc.py
Modified:
   grass-addons/grass7/vector/Makefile
Log:
v.mapcalc: vector map algebra module in Python (authors: Thomas Leppelt and Soeren Gebbert)

Code from:
https://code.google.com/p/grass-gis-temporal-algebra/source/checkout
svn checkout http://grass-gis-temporal-algebra.googlecode.com/svn/trunk/ grass-gis-temporal-algebra-read-only

Developed in GSoC 2014:
https://grasswiki.osgeo.org/wiki/GRASS_GSoC_2013_Temporal_GIS_Algebra_for_raster_and_vector_data_in_GRASS


Modified: grass-addons/grass7/vector/Makefile
===================================================================
--- grass-addons/grass7/vector/Makefile	2016-01-06 03:00:33 UTC (rev 67493)
+++ grass-addons/grass7/vector/Makefile	2016-01-06 03:05:44 UTC (rev 67494)
@@ -32,6 +32,7 @@
 	v.lfp \
 	v.lidar.mcc \
 	v.link.precip \
+	v.mapcalc \
 	v.maxent.swd \
 	v.median \
 	v.mrmr \

Added: grass-addons/grass7/vector/v.mapcalc/Makefile
===================================================================
--- grass-addons/grass7/vector/v.mapcalc/Makefile	                        (rev 0)
+++ grass-addons/grass7/vector/v.mapcalc/Makefile	2016-01-06 03:05:44 UTC (rev 67494)
@@ -0,0 +1,7 @@
+MODULE_TOPDIR = ../../grass7.0/grass_trunk
+
+PGM = v.mapcalc
+
+include $(MODULE_TOPDIR)/include/Make/Script.make
+
+default: script
\ No newline at end of file

Added: grass-addons/grass7/vector/v.mapcalc/v.mapcalc.html
===================================================================
--- grass-addons/grass7/vector/v.mapcalc/v.mapcalc.html	                        (rev 0)
+++ grass-addons/grass7/vector/v.mapcalc/v.mapcalc.html	2016-01-06 03:05:44 UTC (rev 67494)
@@ -0,0 +1,113 @@
+<h2>DESCRIPTION</h2> 
+
+v.mapcalc performs overlay and buffer functions on vector map layers. New vector map layers can be created which are 
+expressions of existing vector map layers, boolean vector operations and buffer functions. 
+
+<h3>PROGRAM USE</h3> 
+The module expects its input as expression in the following form: <br>
+<br>
+<b> result = expression </b>
+<br>
+<br>
+
+This structure is similar to r.mapcalc, see <a href="r.mapcalc.html">r.mapcalc</a>. 
+Where <b>result</b> is the name of a vector map layer that will contain the result of the calculation and 
+<b>expression</b> is any valid combination of boolean and buffer operations for existing vector map layers. <br>
+
+The input is given by using the first module option <i>expression=</i> . This option passes a <b>quoted</b> 
+expression on the command line, for example: <br>
+<div class="code"><pre>v.mapcalc expression="A = B"</pre></div> 
+Where <b>A</b> is the new vector map layer that will be equal to the existing vector map layer <b>B</b> in this case. <br>
+<div class="code"><pre>v.mapcalc "A = B"</pre></div> 
+Will give the same result. 
+<br>
+<br>
+<h3>OPERATORS AND FUNCTIONS</h3>
+
+The module supports the following boolean vector operations: <br>
+<div class="code"><pre>
+ Boolean Name   Operator Meaning         Precedence   Correspondent function 
+---------------------------------------------------------------------------------- 
+ AND            &        Intersection          1      (v.overlay operator=and) 
+ OR             |        Union                 1      (v.overlay operator=or)  
+ DISJOINT OR    +        Disjoint union        1      (v.patch)              
+ XOR            ^        Symmetric difference  1      (v.overlay operator=xor) 
+ NOT            ~        Complement            1      (v.overlay operator=not) 
+
+</pre></div>
+
+And vector functions:
+<div class="code"><pre>
+ buff_p(A, size)    	  Buffer the points of vector map layer A with size
+ buff_l(A, size)    	  Buffer the lines of vector map layer A with size
+ buff_a(A, size)    	  Buffer the areas of vector map layer A with size
+</pre></div>
+<br>
+
+<h2>NOTES</h2>
+As shown in the operator table above, the boolean vector operators do not have different precedence. 
+In default setting the expression will be left associatively evaluated. To define specific precedence use parentheses 
+around these expressions, for example: <br>
+
+<div class="code"><pre>
+ v.mapcalc expression="D = A & B | C"
+</pre></div>
+Here the first intermediate result is the intersection of vector map layers <b>A & B</b>.  
+This intermediate vector map layer is taken to create the union with vector map <b>C</b> to get the final result <b>D</b>.
+It represents the default behaviour of left associativity. 
+
+<div class="code"><pre>
+ v.mapcalc expression="D = A & (B | C)"
+</pre></div>
+Here the first intermediate result is taken from the parenthesized union of vector map layers <b>B | C</b>.  
+Afterwards the intersection of the intermediate vector map layer and <b>A</b> will be evaluated to get the final 
+result vector map layer <b>D</b>.
+<br>
+<br>
+It should be noticed, that the order in which the operations are performed does matter. 
+Different order of operations can lead to a different result.
+
+<h2>EXAMPLES</h2>
+This example needed specific region setting. It should work in UTM and LL test locations. <br>
+First set the regions extent and create two vector maps with one random points, respectively:
+<div class="code"><pre>
+g.region s=0 n=80 w=0 e=120 b=0 t=50 res=10 res3=10 -p3
+
+v.random --o -z output=point_1 n=1 seed=1 
+v.info point_1
+v.random --o -z output=point_2 n=1 seed=2 
+v.info point_2
+</pre></div>
+
+Then the vector algebra is used to create buffers around those points, cut out a subset and apply different boolean operation on the subsets in one statement:
+<div class="code"><pre>
+v.mapcalc --o expr="buff_and = (buff_p(point_1, 30.0) ~ buff_p(point_1, 20.0)) & \
+                    (buff_p(point_2, 35) ~ buff_p(point_2, 25))"
+v.mapcalc --o expr="buff_or  = (buff_p(point_1, 30.0) ~ buff_p(point_1, 20.0)) | \
+                    (buff_p(point_2, 35) ~ buff_p(point_2, 25))"
+v.mapcalc --o expr="buff_xor = (buff_p(point_1, 30.0) ~ buff_p(point_1, 20.0)) ^ \
+                    (buff_p(point_2, 35) ~ buff_p(point_2, 25))"
+v.mapcalc --o expr="buff_not = (buff_p(point_1, 30.0) ~ buff_p(point_1, 20.0)) ~ \
+                    (buff_p(point_2, 35) ~ buff_p(point_2, 25))"
+</pre></div>
+
+<h2>REFERENCES</h2>
+
+<tt><a href="http://www.dabeaz.com/ply/">PLY(Python-Lex-Yacc)</a></tt>
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="v.overlay.html">v.overlay</a>,
+<a href="v.buffer.html">v.buffer</a>,
+<a href="v.patch.html">v.patch</a>,
+<a href="r.mapcalc.html">r.mapcalc</a>
+</em>
+
+
+<h2>AUTHOR</h2>
+
+Thomas Leppelt, Soeren Gebbert, Thuenen Institut, Germany <br>
+
+<p><i>Last changed: $Date: 2013-06-12 11:35:20 +0100 (Wed, 12 Jun 2013) $</i>
+

Added: grass-addons/grass7/vector/v.mapcalc/v.mapcalc.py
===================================================================
--- grass-addons/grass7/vector/v.mapcalc/v.mapcalc.py	                        (rev 0)
+++ grass-addons/grass7/vector/v.mapcalc/v.mapcalc.py	2016-01-06 03:05:44 UTC (rev 67494)
@@ -0,0 +1,408 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+############################################################################
+#
+# MODULE:       v.mapcalc
+# AUTHOR(S):    Thomas Leppelt, Soeren Gebbert, Thünen Institut Germany,
+#
+# PURPOSE:      Vector map algebra
+# 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.
+#
+#############################################################################
+
+#%module
+#% description: Vector algebra
+#% keywords: vector, mapcalc, algebra
+#%end
+#%option
+#% key: expression
+#% type: string
+#% description: The vector mapcalc expression
+#% key_desc: expression
+#% required : yes
+#%end
+
+import ply.lex as lex
+import ply.yacc as yacc
+import sys
+import re
+import os
+from grass.script import core as grass
+import grass.pygrass.modules as mod
+
+class CmdMapList(object):
+    """Listing and execution of PyGRASS module objects"""
+    def __init__(self):
+        self.exec_list = []
+    # Execute command list.
+    def exec_cmd_list(self):
+        for cmd in self.exec_list:
+            cmd.run()
+            if cmd.popen.returncode != 0:
+                grass.ScriptError("Error starting %s : \n%s"%(cmd.get_bash(), \
+                                                              cmd.popen.stderr))
+    # Print command list. 
+    def get_cmd_list(self):
+        print(self.exec_list)
+    # Add new command to list.
+    def add_cmd(self, newcmd):
+        self.exec_list.append(newcmd)
+        
+class VectorAlgebraLexer(object):
+    """!Lexical analyzer for the GRASS GIS vector algebra"""
+    
+    # Buffer functions from v.buffer
+    vector_buff_functions = {
+       'buff_p'  : 'BUFF_POINT',
+       'buff_l'   : 'BUFF_LINE',
+       'buff_a'   : 'BUFF_AREA'
+    }   
+
+    # This is the list of token names.
+    tokens = (
+        'INT', 
+        'FLOAT',
+        'LPAREN',
+        'RPAREN',
+        'COMMA',
+        'EQUALS',
+        'SYMBOL',
+        'NAME',
+        'AND',  # v.overlay
+        'NOT',  # v.overlay
+        'OR',  # v.overlay
+        'XOR',  # v.overlay
+        'DISOR', # v.patch
+    )
+
+    # Build the token list
+    tokens = tokens + tuple(vector_buff_functions.values())
+
+    # Regular expression rules for simple tokens
+    t_LPAREN  = r'\('
+    t_RPAREN  = r'\)'
+    t_COMMA   = r','
+    t_EQUALS  = r'='
+    t_AND     = r'&'
+    t_NOT     = r'\~'
+    t_OR      = r'\|'
+    t_XOR     = r'\^'
+    t_DISOR   = r'\+'
+    
+    # These are the things that should be ignored.
+    t_ignore = ' \t'
+    
+    def __init__(self):
+        self.name_list = {}
+
+    # Read in a float. This rule has to be done before the int rule.
+    def t_FLOAT(self, t):
+        r'-?\d+\.\d*(e-?\d+)?'
+        t.value = float(t.value)
+        return t
+        
+    # Read in an int.
+    def t_INT(self, t):
+        r'-?\d+'
+        t.value = int(t.value)
+        return t
+        
+    # Ignore comments.
+    def t_comment(self, t):
+        r'[#][^\n]*'
+        pass
+        
+    # Track line numbers.
+    def t_newline(self, t):
+        r'\n+'
+        t.lineno += len(t.value)
+
+    # Parse symbols
+    def t_SYMBOL(self, t):
+        r'[a-zA-Z_][a-zA-Z_0-9]*'
+        # Check for reserved words
+        if t.value in VectorAlgebraLexer.vector_buff_functions.keys():
+            t.type = VectorAlgebraLexer.vector_buff_functions.get(t.value)
+        else:
+            t.type = 'NAME'
+            self.name_list[t.value] = t.value
+        return t
+
+    # Handle errors.
+    def t_error(self, t):
+        raise SyntaxError("syntax error on line %d near '%s'" % 
+            (t.lineno, t.value))
+
+    # Build the lexer
+    def build(self,**kwargs):
+        self.lexer = lex.lex(module=self, **kwargs)
+        
+    # Just for testing
+    def test(self,data):
+        self.name_list = {}
+        self.lexer.input(data)
+        while True:
+             tok = self.lexer.token()
+             if not tok: break
+             print tok
+
+class VectorAlgebraParser(object):
+    """This is the vector algebra parser class"""
+
+    # Get the tokens from the lexer class
+    tokens = VectorAlgebraLexer.tokens
+    
+    # Setting equal precedence level for boolean operations.
+    precedence = (
+        ('left', 'AND', 'OR', 'NOT', 'XOR', 'DISOR'), # 1
+        )
+    
+    def __init__(self, pid=None, run=True, debug=False):
+        self.run = run
+        self.debug = debug
+        self.pid = pid
+        self.lexer = VectorAlgebraLexer()
+        self.lexer.build()
+        # Intermediate vector map names 
+        self.names = {}
+        # Count map names
+        self.count = 0
+        self.parser = yacc.yacc(module=self)
+        # Create empty command list object
+        self.cmdlist = CmdMapList()        
+        
+    def parse(self, expression):
+        self.count = 0
+        self.parser.parse(expression)
+        
+    def generate_vector_map_name(self):
+        """!Generate an unique intermediate vector map name 
+           and register it in the objects map list for later removement.
+           
+           The vector map names are unique between processes. Do not use the
+           same object for map name generation in multiple threads.
+        """
+        self.count += 1
+        if self.pid != None:
+            pid = self.pid
+        else:
+            pid = os.getpid()
+        name = "tmp_vect_name_%i_%i"%(pid, self.count)
+        self.names[name] = name
+        #print(name)
+        return name
+    
+    def p_statement_assign(self,t):
+        """
+        statement : NAME EQUALS expression
+                  | NAME EQUALS name
+                  | NAME EQUALS paren_name
+        """
+        # We remove the invalid vector name from the list
+        if self.names.has_key(t[3]):
+            self.names.pop(t[3])
+        
+        # We rename the resulting vector map
+        if self.debug:
+            print "g.rename vector=%s,%s"%(t[3],t[1])
+
+	if self.run:
+	    m = mod.Module("g.rename", vect=(t[3],t[1]), overwrite=grass.overwrite, 
+	                   run_ = False)
+	    self.cmdlist.add_cmd(m)
+        self.remove_intermediate_vector_maps()
+
+    def remove_intermediate_vector_maps(self):
+        if self.debug:
+            for name in self.names:
+                print "g.remove vect=%s"%(name)
+        if self.run:
+	    for name in self.names:
+	        m = mod.Module("g.remove", vect=name, run_ = False)
+	        self.cmdlist.add_cmd(m)
+		    
+    def p_bool_and_operation(self, t):
+        """
+        expression : name AND name
+                   | expression AND name
+                   | name AND expression
+                   | expression AND expression                   
+                   | name OR name
+                   | expression OR name
+                   | name OR expression
+                   | expression OR expression
+                   | name XOR name
+                   | expression XOR name
+                   | name XOR expression
+                   | expression XOR expression 
+                   | name NOT name
+                   | expression NOT name
+                   | name NOT expression
+                   | expression NOT expression
+                   | name DISOR name                
+                   | expression DISOR name                   
+                   | name DISOR expression                   
+                   | expression DISOR expression        
+        """
+
+        # Generate an intermediate name
+        name = self.generate_vector_map_name()
+        
+        # Assign ids to expressions, names and operators.
+	firstid = 1
+	secondid = 3
+	operatorid = 2
+	    
+	# Define operation commands. 
+        if t[operatorid] == "&":
+            if self.debug:
+                print "v.overlay operator=and ainput=%s binput=%s output=%s"\
+                      %(t[firstid], t[secondid], name)
+
+	    if self.run:
+		m = mod.Module("v.overlay", operator="and", ainput=t[firstid], \
+		               binput=t[secondid], output=name, run_ = False)
+		self.cmdlist.add_cmd(m)
+            t[0] = name
+            
+        elif t[operatorid] == "|":
+            if self.debug:
+                print "v.overlay operator=or ainput=%s binput=%s output=%s"\
+                       %(t[firstid], t[secondid], name)
+
+	    if self.run:
+		m = mod.Module("v.overlay", operator="or", ainput=t[firstid], \
+		               binput=t[secondid], output=name, run_ = False)
+		self.cmdlist.add_cmd(m)
+            t[0] = name
+            
+        elif t[operatorid] == "^":
+            if self.debug:
+                print "v.overlay operator=xor ainput=%s binput=%s output=%s"\
+                      %(t[firstid], t[secondid], name)
+
+	    if self.run:
+		m = mod.Module("v.overlay", operator="xor", ainput=t[firstid], \
+		               binput=t[secondid], output=name, run_ = False)
+		self.cmdlist.add_cmd(m)
+            t[0] = name
+            
+        elif t[operatorid] == "~":
+            if self.debug:
+                print "v.overlay operator=not ainput=%s binput=%s output=%s"\
+                      %(t[firstid], t[secondid], name)
+
+	    if self.run:
+		m = mod.Module("v.overlay", operator="not", ainput=t[firstid], \
+		               binput=t[secondid], output=name, run_ = False)
+		self.cmdlist.add_cmd(m)
+            t[0] = name
+            
+        elif t[operatorid] == "+":
+	    patchinput = t[firstid] + ',' + t[secondid]
+            if self.debug:
+                print "v.patch input=%s output=%s"\
+                      %(patchinput, name)
+
+	    if self.run:
+		m = mod.Module("v.patch", input=patchinput, output=name, run_ = False)
+		self.cmdlist.add_cmd(m)
+            t[0] = name
+        
+    def p_buffer_operation(self,t):
+        """
+        expression : buff_function LPAREN name COMMA number RPAREN 
+                   | buff_function LPAREN expression COMMA number RPAREN
+                   """
+        # Generate an intermediate name
+        name = self.generate_vector_map_name()
+
+        # Assign ids to expressions, names and operators.
+	mapid = 3
+	operatorid = 5
+	    
+        if t[1] == "buff_p":
+            if self.debug:
+                print "v.buffer input=%s type=point distance=%g output=%s"\
+                      %(t[mapid], t[operatorid], name)
+  
+	    if self.run:
+		m = mod.Module("v.buffer", type="point", input=t[mapid], \
+		               distance=float(t[operatorid]), output=name, \
+		               run_ = False)
+		self.cmdlist.add_cmd(m)
+            t[0] = name
+        elif t[1] == "buff_l":
+            if self.debug:
+                print "v.buffer input=%s type=line distance=%g output=%s"\
+                       %(t[mapid], t[operatorid], name)
+
+	    if self.run:
+		m = mod.Module("v.buffer", type="line", input=t[mapid], \
+		               distance=float(t[operatorid]), output=name, \
+		               run_ = False)
+		self.cmdlist.add_cmd(m)
+            t[0] = name
+        elif t[1] == "buff_a":
+            if self.debug:
+                print "v.buffer input=%s type=area distance=%g output=%s"\
+                      %(t[mapid], t[operatorid], name)
+
+	    if self.run:
+		m = mod.Module("v.buffer", type="area", input=t[mapid], \
+		               distance=float(t[operatorid]), output=name, \
+		               run_ = False)
+		self.cmdlist.add_cmd(m)
+            t[0] = name
+	    
+    def p_paren_expr(self, t):
+        """ expression : LPAREN expression RPAREN"""
+        t[0] = t[2]
+        
+    def p_number_int(self, t):
+        """number : INT"""
+        t[0] = t[1]
+        
+    def p_number_float(self, t):
+        """number : FLOAT"""
+        t[0] = t[1]
+        
+    def p_name(self, t):
+        """name : NAME
+                | SYMBOL
+                """
+        t[0] = t[1]
+
+    def p_paren_name(self, t):
+        """paren_name : LPAREN NAME RPAREN
+                      | LPAREN SYMBOL RPAREN
+                      """
+        t[0] = t[2]
+        
+    def p_buff_function(self, t):
+        """buff_function    : BUFF_POINT
+                            | BUFF_LINE
+                            | BUFF_AREA
+                            """
+        t[0] = t[1]
+        
+    # Error rule for syntax errors.
+    def p_error(self,t):
+        raise SyntaxError("invalid syntax")
+
+def main():
+    expression = options['expression']
+
+    p = VectorAlgebraParser(run = True, debug=False)
+    p.parse(expression)
+    p.cmdlist.get_cmd_list()
+    p.cmdlist.exec_cmd_list()
+
+if __name__ == "__main__":
+    options, flags = grass.parser()
+    sys.exit(main())
+



More information about the grass-commit mailing list