[GRASS-SVN] r53266 - in grass-addons/grass7/vector: . v.in.wfs2

svn_grass at osgeo.org svn_grass at osgeo.org
Fri Sep 21 17:12:26 PDT 2012


Author: turek
Date: 2012-09-21 17:12:25 -0700 (Fri, 21 Sep 2012)
New Revision: 53266

Added:
   grass-addons/grass7/vector/v.in.wfs2/
   grass-addons/grass7/vector/v.in.wfs2/Makefile
   grass-addons/grass7/vector/v.in.wfs2/v.in.wfs2.html
   grass-addons/grass7/vector/v.in.wfs2/v.in.wfs2.py
   grass-addons/grass7/vector/v.in.wfs2/wfs_base.py
   grass-addons/grass7/vector/v.in.wfs2/wfs_drv.py
   grass-addons/grass7/vector/v.in.wfs2/wfs_owslib_drv.py
Log:
v.in.wfs2: experimental version

Added: grass-addons/grass7/vector/v.in.wfs2/Makefile
===================================================================
--- grass-addons/grass7/vector/v.in.wfs2/Makefile	                        (rev 0)
+++ grass-addons/grass7/vector/v.in.wfs2/Makefile	2012-09-22 00:12:25 UTC (rev 53266)
@@ -0,0 +1,18 @@
+MODULE_TOPDIR = ../..
+
+PGM = v.in.wfs2
+
+MODULES = wfs_base wfs_drv wfs_owslib_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) $< $@


Property changes on: grass-addons/grass7/vector/v.in.wfs2/Makefile
___________________________________________________________________
Added: svn:executable
   + *

Added: grass-addons/grass7/vector/v.in.wfs2/v.in.wfs2.html
===================================================================
--- grass-addons/grass7/vector/v.in.wfs2/v.in.wfs2.html	                        (rev 0)
+++ grass-addons/grass7/vector/v.in.wfs2/v.in.wfs2.html	2012-09-22 00:12:25 UTC (rev 53266)
@@ -0,0 +1,28 @@
+<h2>DESCRIPTION</h2>
+
+<em>v.in.wfs2</em> imports OGC WFS maps (Web Feature Service) from
+external servers.
+
+
+<h2>EXAMPLES</h2>
+
+Parks in Canada:
+<p><div class="code"><pre>
+v.in.wfs2 url=http://www2.dmsolutions.ca/cgi-bin/mswfs_gmap output=parks srs=42304 layers=park wfs_version=1.1.0 
+</pre></div>
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="g.region.html">g.region</a>,
+<a href="r.in.wms.html">r.in.wms</a>,
+<a href="v.in.ogr.html">v.in.ogr</a>
+</em>
+
+
+<h2>AUTHORS</h2>
+
+Štěpán Turek
+
+<p>
+<i>Last changed: $Date$</i>

Added: grass-addons/grass7/vector/v.in.wfs2/v.in.wfs2.py
===================================================================
--- grass-addons/grass7/vector/v.in.wfs2/v.in.wfs2.py	                        (rev 0)
+++ grass-addons/grass7/vector/v.in.wfs2/v.in.wfs2.py	2012-09-22 00:12:25 UTC (rev 53266)
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+"""
+MODULE:    v.in.wfs2
+
+AUTHOR(S): Stepan Turek <stepan.turek AT seznam.cz>
+
+PURPOSE:   Downloads and imports data from WFS 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 WFS server.
+#% keywords: vector
+#% keywords: import
+#% keywords: wfs
+#%end
+
+#%option
+#% key: url
+#% type: string
+#% description:URL of WFS server 
+#% required: yes
+#%end
+
+#%option
+#% key: layers
+#% type: string
+#% description: Layers to request from server
+#% multiple: yes
+#% required: yes
+#%end
+
+#%option G_OPT_V_OUTPUT
+#% description: Name for output vector map
+#%end
+
+
+#%option
+#% key: srs
+#% type: integer
+#% description: EPSG number of source projection for request 
+#% answer:4326 
+#% guisection: Request properties
+#%end
+
+#%flag
+#% key: r
+#% description: Restrict fetch to features which touch the region
+#% guisection: Request properties
+#%end
+
+#%option
+#% key: region
+#% type: string
+#% description: Named region to request data for (only with r flag)
+#% guisection: Request properties
+#%end
+
+#%option
+#% key: wfs_version
+#% type:string
+#% description:WFS standard
+#% options:1.1.0, 1.0.0
+#% answer:1.1.0
+#% guisection: Request properties
+#%end
+
+#%option
+#% key: maximum_features
+#% type: integer
+#% label: Maximum number of features to download
+#% description: (default: unlimited)
+#% guisection: Request properties
+#%end
+
+#%option
+#% key: urlparams
+#% type:string
+#% description: Addition query parameters for server (only with GRASS driver)
+#% guisection: Request properties
+#%end
+
+#%flag
+#% key: c
+#% description: Get capabilities
+#% guisection: Request properties
+#% suppress_required: yes
+#%end
+
+#%option
+#% key: driver
+#% type:string
+#% description:WFS driver
+#% options:WFS_GRASS, WFS_OSWLib
+#% answer:WFS_GRASS
+#%end
+
+
+import os
+import sys
+sys.path.insert(1, os.path.join(os.path.dirname(sys.path[0]), 'etc', 'v.in.wfs2'))
+
+import grass.script as grass
+
+def main():
+
+    if options['driver'] == 'WFS_GRASS':
+        grass.debug("Using GRASS driver")
+        from wfs_drv import WFSDrv
+        wfs = WFSDrv()
+    else:
+        grass.debug("Using OSWLib driver")
+        from wfs_owslib_drv import WFSOwsLibDrv
+        wfs = WFSOwsLibDrv()
+    
+    if flags['c']:
+        wfs.GetCapabilities(options)
+    else:
+        wfs.GetFeature(options, flags)    
+   
+    return 0
+
+if __name__ == "__main__":
+    options, flags = grass.parser()
+    sys.exit(main())


Property changes on: grass-addons/grass7/vector/v.in.wfs2/v.in.wfs2.py
___________________________________________________________________
Added: svn:executable
   + *

Added: grass-addons/grass7/vector/v.in.wfs2/wfs_base.py
===================================================================
--- grass-addons/grass7/vector/v.in.wfs2/wfs_base.py	                        (rev 0)
+++ grass-addons/grass7/vector/v.in.wfs2/wfs_base.py	2012-09-22 00:12:25 UTC (rev 53266)
@@ -0,0 +1,282 @@
+import os
+from   math import ceil
+
+from urllib2 import urlopen, HTTPError, URLError
+
+import grass.script as grass
+
+class WFSBase:
+    def __init__(self):
+        # these variables are information for destructor
+        self.temp_to_cleanup = []
+        
+        self.bbox     = None
+        self.temp_map = None
+        
+    def __del__(self):
+        
+        # tries to remove temporary files/dirs, all temps should be
+        # removoved before, implemented just in case of unexpected
+        # stop of module
+        for temp in self.temp_to_cleanup:
+            if os.path.isdir(temp):
+                grass.try_rmdir(temp)
+            else:
+                grass.try_remove(temp)
+                
+        # deletes enviromental 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.o_url = options['url'].strip() + "?" 
+        self.o_layers = options['layers'].strip()
+        self.o_output = options['output']
+        
+        self.o_wds_version = options['wfs_version']        
+        self.projection_name = "SRSNAME" 
+ 
+        self.o_wfs_version = options['wfs_version']
+       
+        self.o_urlparams = options['urlparams'].strip()
+        
+        self.o_srs = int(options['srs'])
+        if self.o_srs <= 0:
+            grass.fatal(_("Invalid EPSG code %d") % self.o_srs)
+        
+        try:
+            self.o_maximum_features = int(options['maximum_features'])
+            if int(options['maximum_features']) < 1:
+                grass.fatal(_('Invalid maximum number of features (must be >1)'))
+        except ValueError:
+            self.o_maximum_features = None
+
+        # read projection info
+        self.proj_location = grass.read_command('g.proj', 
+                                                flags ='jf').rstrip('\n')
+
+        self.proj_srs = grass.read_command('g.proj', 
+                                           flags = 'jf', 
+                                           epsg = str(self.o_srs) ).rstrip('\n')
+        
+        if not self.proj_srs or not self.proj_location:
+            grass.fatal(_("Unable to get projection info"))
+        
+        # set region 
+        self.o_region = options['region']
+        if self.o_region:                 
+            if not grass.find_file(name = self.o_region, element = 'windows', mapset = '.' )['name']:
+                grass.fatal(_("Region <%s> not found") % self.o_region)
+        
+        if self.o_region:
+            s = grass.read_command('g.region',
+                                   quiet = True,
+                                   flags = 'ug',
+                                   region = self.o_region)
+            self.region = grass.parse_key_val(s, val_type = float)
+        else:
+            self.region = grass.region()
+
+        self.ogr_drv_format = "ESRI Shapefile"             
+        self._debug("_initialize_parameters", "finished")
+
+    def GetFeature(self, options, flags):
+        """!Download data from WFS server and import data
+            into GRASS as a vector map."""
+
+        self._initializeParameters(options, flags)  
+
+        if flags['r']:
+            self.bbox = self._computeBbox()
+        else:
+            self.bbox = None
+
+        self.temp_map = self._download()  
+
+        self._createOutputMap() 
+    
+    def GetCapabilities(self, options): 
+        """!Get capabilities from WFS server
+        """
+        # download capabilities file
+        cap_url = options['url'] + "?service=WFS&request=GetCapabilities&version=" + options['wfs_version'] 
+        try:
+            cap = urlopen(cap_url)
+        except IOError:
+            grass.fatal(_("Unable to get capabilities from '%s'") % options['url'])
+        
+        cap_lines = cap.readlines()
+        for line in cap_lines: 
+            print line 
+        
+    def _computeBbox(self):
+        """!Get region extent for WFS 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 wfs query projection are
+        # different, corner points of region are transformed into wfs
+        # 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._temp()
+            
+            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 defintion: 4 points required"))
+            
+            for point in points:
+                point = map(float, point.split("|"))
+                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 is fliped If self.flip_coords is 
+        # True, coords in bbox need to be flipped in WFS query.
+
+        self.flip_coords = False  
+        hasLongLat = self.proj_srs.find("+proj=longlat")   
+        hasLatLong = self.proj_srs.find("+proj=latlong")   
+
+        if (hasLongLat != -1 or hasLatLong != -1):
+            self.flip_coords = True
+
+        return bbox
+
+    def _createOutputMap(self): 
+        """!Import downloaded data into GRASS, reproject data if needed
+        using ogr2ogr
+        """
+        # reprojection of downloaded data
+        if self.proj_srs != self.proj_location: # TODO: do it better
+            grass.message(_("Reprojecting data..."))
+            temp_warpmap = self._temp()
+            
+            if int(os.getenv('GRASS_VERBOSE', '2')) <= 2:
+                nuldev = file(os.devnull, 'w+')
+            else:
+                nuldev = None
+            
+            temp_warpmap = self._temp(directory = True)
+
+            ps = grass.Popen(['ogr2ogr',
+                              '-overwrite',
+                              '-s_srs', '%s' % self.proj_srs,
+                              '-t_srs', '%s' % self.proj_location,
+                              '-f',     '%s' % self.ogr_drv_format, 
+                              temp_warpmap, self.temp_map], stdout = nuldev)
+            ps.wait()
+            
+            if nuldev:
+                nuldev.close()
+            
+            if ps.returncode != 0:
+                grass.fatal(_('%s failed') % 'ogr2ogr')
+        # downloaded data projection is same as projection of location
+        else:
+            temp_warpmap = self.temp_map
+        
+        grass.message(_("Importing vector map into GRASS..."))
+        # importing temp_map into GRASS
+        if grass.run_command('v.in.ogr',
+                             quiet = True,
+                             overwrite = True,
+                             dsn = temp_warpmap,
+                             output = self.o_output) != 0:
+            grass.fatal(_('%s failed') % 'v.in.ogr')
+        
+        grass.try_rmdir(temp_warpmap)
+        grass.try_remove(self.temp_map) 
+
+    def _flipBbox(self, bbox):
+        """ 
+        flips items in dictionary 
+        value flips between this keys:
+        maxy -> maxx
+        maxx -> maxy
+        miny -> minx
+        minx -> miny
+        @return copy of bbox with fliped cordinates
+        """  
+        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
+
+    def _temp(self, directory = False):
+        """!Create temp file/dir and append list self.temp_to_cleanup 
+            with the file/dir path 
+     
+        @param directory if False create file, if True create directory
+
+        @return string path to temp
+        """
+        if directory:
+            temp = grass.tempdir()
+        else:
+            temp = grass.tempfile()
+
+        if temp is None:
+            grass.fatal(_("Unable to create temporary files"))
+        
+        # list of created temps for destructor
+        self.temp_to_cleanup.append(temp)
+        
+        return temp


Property changes on: grass-addons/grass7/vector/v.in.wfs2/wfs_base.py
___________________________________________________________________
Added: svn:executable
   + *

Added: grass-addons/grass7/vector/v.in.wfs2/wfs_drv.py
===================================================================
--- grass-addons/grass7/vector/v.in.wfs2/wfs_drv.py	                        (rev 0)
+++ grass-addons/grass7/vector/v.in.wfs2/wfs_drv.py	2012-09-22 00:12:25 UTC (rev 53266)
@@ -0,0 +1,84 @@
+import grass.script as grass 
+
+from urllib2 import urlopen
+import xml.etree.ElementTree as etree
+
+import numpy as Numeric
+Numeric.arrayrange = Numeric.arange
+
+from wfs_base import WFSBase
+
+class WFSDrv(WFSBase):
+    def _download(self):
+        """!Downloads data from WFS server 
+        
+        @return temp_map with downloaded data
+        """ 
+        grass.message(_("Downloading data from WFS server..."))
+
+        proj = self.projection_name + "=EPSG:"+ str(self.o_srs)
+
+        url = self.o_url + ("SERVICE=WFS&REQUEST=GetFeature&VERSION=%s&TYPENAME=%s" % \
+             (self.o_wfs_version, self.o_layers))
+
+        if self.bbox:
+            if self.flip_coords:
+                # flip coordinates if projection is geographic (see:wfs_base.py _computeBbox)
+                query_bbox = dict(self._flipBbox(self.bbox))
+            else:
+                query_bbox = self.bbox
+
+            url += "&BBOX=%s,%s,%s,%s" % \
+                   (query_bbox['minx'],  query_bbox['miny'],  query_bbox['maxx'],  query_bbox['maxy']) 
+        
+        if self.o_maximum_features:
+            url += '&MAXFEATURES=' +  str(self.o_maximum_features)
+
+        if self.o_urlparams != "":
+            url +="&" + self.o_urlparams
+        
+        grass.debug(url)
+        try: 
+            wfs_data = urlopen(url)
+        except IOError:
+            grass.fatal(_("Unable to fetch data from server"))
+        
+        temp_map = self._temp()
+
+        # download data into temporary file
+        try:
+            temp_map_opened = open(temp_map, 'w')
+            temp_map_opened.write(wfs_data.read())
+            temp_map_opened
+        except IOError:
+            grass.fatal(_("Unable to write data into tempfile"))
+        finally:
+            temp_map_opened.close()
+
+        namespaces =  ['http://www.opengis.net/ows',
+                       'http://www.opengis.net/ogc']
+
+        context = etree.iterparse(temp_map, events=["start"])
+        event, root = context.next()
+
+        for namesp in namespaces:
+            if root.tag == "{%s}ExceptionReport" % namesp or \
+                root.tag == "{%s}ServiceExceptionReport" % namesp:
+                try:
+                    error_xml_opened = open(temp_map, '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(_("WFS server error: %s") %  err_str)
+                else:
+                    grass.fatal(_("WFS server unknown error") )
+
+        return temp_map
+    
+   
+
+


Property changes on: grass-addons/grass7/vector/v.in.wfs2/wfs_drv.py
___________________________________________________________________
Added: svn:executable
   + *

Added: grass-addons/grass7/vector/v.in.wfs2/wfs_owslib_drv.py
===================================================================
--- grass-addons/grass7/vector/v.in.wfs2/wfs_owslib_drv.py	                        (rev 0)
+++ grass-addons/grass7/vector/v.in.wfs2/wfs_owslib_drv.py	2012-09-22 00:12:25 UTC (rev 53266)
@@ -0,0 +1,52 @@
+import grass.script as grass 
+try:
+    from owslib.wfs import WebFeatureService
+    from owslib.util import ServiceException
+except:
+    grass.fatal(_("OSWLib can not be found. Install OSWLib (http://geopython.github.com/OWSLib/) or use GRASS driver."))
+
+from wfs_base import WFSBase
+
+class WFSOwsLibDrv(WFSBase):
+    def _download(self):
+        """!Downloads data from WFS server using OSWlLib driver
+        
+        @return temp_map with downloaded data
+        """ 
+        grass.message(_("Downloading data from WFS server..."))
+
+        if self.bbox:
+            query_bbox = (self.bbox['minx'],  self.bbox['miny'],  self.bbox['maxx'],  self.bbox['maxy'])
+        else:
+            query_bbox = self.bbox
+
+        wfs = WebFeatureService(url = self.o_url, version= self.o_wfs_version)
+  
+        try:
+            wfs_data = wfs.getfeature( typename = [self.o_layers],
+                                       srsname =  "EPSG:" + str(self.o_srs),
+                                       maxfeatures = self.o_maximum_features,
+                                       bbox = query_bbox)   
+        #TODO do it better                                         
+        except ServiceException, e:
+            grass.fatal(_("Server returned exception"))
+
+        grass.debug(url)
+
+        temp_map = self._temp()
+                
+        # download data into temporary file
+        try:
+            temp_map_opened = open(temp_map, 'w')
+            temp_map_opened.write(wfs_data.read())
+            temp_map_opened
+        except IOError:
+            grass.fatal(_("Unable to write data into tempfile"))
+        finally:
+            temp_map_opened.close()
+
+        return temp_map
+    
+   
+
+


Property changes on: grass-addons/grass7/vector/v.in.wfs2/wfs_owslib_drv.py
___________________________________________________________________
Added: svn:executable
   + *



More information about the grass-commit mailing list