[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