123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- import os
- from math import ceil
- import xml.etree.ElementTree as etree
- from urllib2 import urlopen, HTTPError, URLError
- import grass.script as grass
- class WMSBase:
- def __init__(self):
- # these variables are information for destructor
- self.temp_files_to_cleanup = []
- self.cleanup_mask = False
- self.cleanup_layers = False
-
- self.bbox = None
- self.temp_map = None
-
- def __del__(self):
- # removes temporary mask, used for import transparent or warped temp_map
- if self.cleanup_mask:
- # clear temporary mask, which was set by module
- if grass.run_command('r.mask',
- quiet = True,
- flags = 'r') != 0:
- grass.fatal(_('%s failed') % 'r.mask')
-
- # restore original mask, if exists
- if grass.find_file(self.o_output + self.original_mask_suffix, element = 'cell', mapset = '.' )['name']:
- if grass.run_command('g.copy',
- quiet = True,
- rast = self.o_output + self.original_mask_suffix + ',MASK') != 0:
- grass.fatal(_('%s failed') % 'g.copy')
-
- # tries to remove temporary files, all files should be
- # removoved before, implemented just in case of unexpected
- # stop of module
- for temp_file in self.temp_files_to_cleanup:
- grass.try_remove(temp_file)
-
- # remove temporary created rasters
- if self.cleanup_layers:
- maps = []
- for suffix in ('.red', '.green', '.blue', '.alpha', self.original_mask_suffix):
- rast = self.o_output + suffix
- if grass.find_file(rast, element = 'cell', mapset = '.')['file']:
- maps.append(rast)
-
- if maps:
- grass.run_command('g.remove',
- quiet = True,
- flags = 'f',
- rast = ','.join(maps))
-
- # deletes 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")
-
- # inicialization of module parameters (options, flags)
- self.flags = flags
- if self.flags['o']:
- self.transparent = 'FALSE'
- else:
- self.transparent = 'TRUE'
-
- self.o_mapserver_url = options['mapserver'].strip() + "?"
- self.o_layers = options['layers'].strip()
- self.o_styles = options['styles'].strip()
- self.o_output = options['output']
- self.o_method = options['method']
-
- self.o_bgcolor = options['bgcolor'].strip()
- if self.o_bgcolor != "" and not flags["d"]:
- grass.warning(_("Parameter bgcolor ignored, use -d flag"))
-
- self.o_urlparams = options['urlparams'].strip()
- if self.o_urlparams != "" and not flags["d"]:
- grass.warning(_("Parameter urlparams ignored, use -d flag"))
-
- self.o_wms_version = options['wms_version']
- if self.o_wms_version == "1.3.0":
- self.projection_name = "CRS"
- else:
- self.projection_name = "SRS"
-
- self.o_format = options['format']
- if self.o_format == "geotiff":
- self.mime_format = "image/geotiff"
- elif self.o_format == "tiff":
- self.mime_format = "image/tiff"
- elif self.o_format == "png":
- self.mime_format = "image/png"
- elif self.o_format == "jpeg":
- self.mime_format = "image/jpeg"
- if flags['o']:
- grass.warning(_("JPEG format does not support transparency"))
- elif self.o_format == "gif":
- self.mime_format = "image/gif"
- else:
- self.mime_format = self.o_format
-
- self.o_srs = int(options['srs'])
- if self.o_srs <= 0:
- grass.fatal(_("Invalid EPSG code %d") % self.o_srs)
-
- # 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()
-
- min_tile_size = 100
- self.o_maxcols = int(options['maxcols'])
- if self.o_maxcols <= min_tile_size:
- grass.fatal(_("Maxcols must be greater than 100"))
-
- self.o_maxrows = int(options['maxrows'])
- if self.o_maxrows <= min_tile_size:
- grass.fatal(_("Maxrows must be greater than 100"))
-
- # setting optimal tile size according to maxcols and maxrows constraint and region cols and rows
- self.tile_cols = int(self.region['cols'] / ceil(self.region['cols'] / float(self.o_maxcols)))
- self.tile_rows = int(self.region['rows'] / ceil(self.region['rows'] / float(self.o_maxrows)))
-
- # suffix for existing mask (during overriding will be saved
- # into raster named:self.o_output + this suffix)
- self.original_mask_suffix = "_temp_MASK"
-
- # check names of temporary rasters, which module may create
- maps = []
- for suffix in ('.red', '.green', '.blue', '.alpha', self.original_mask_suffix ):
- rast = self.o_output + suffix
- if grass.find_file(rast, element = 'cell', mapset = '.')['file']:
- maps.append(rast)
-
- if len(maps) != 0:
- grass.fatal(_("Please change output name, or change names of these rasters: %s, "
- "module needs to create this temporary maps during runing") % ",".join(maps))
-
- # default format for GDAL library
- self.gdal_drv_format = "GTiff"
-
- self._debug("_initialize_parameters", "finished")
- def GetMap(self, options, flags):
- """!Download data from WMS server and import data
- (using GDAL library) into GRASS as a raster map."""
- self._initializeParameters(options, flags)
- self.bbox = self._computeBbox()
-
- self.temp_map = self._download()
-
- self._createOutputMap()
-
- def GetCapabilities(self, options):
- """!Get capabilities from WMS server
- """
- # download capabilities file
- cap_url = options['mapserver'] + "?service=WMS&request=GetCapabilities&version=" + options['wms_version']
- try:
- cap = urlopen(cap_url)
- except IOError:
- grass.fatal(_("Unable to get capabilities from '%s'") % options['mapserver'])
-
- cap_lines = cap.readlines()
- for line in cap_lines:
- print line
-
- def _computeBbox(self):
- """!Get region extent for WMS query (bbox)
- """
- self._debug("_computeBbox", "started")
-
- bbox_region_items = {'maxy' : 'n', 'miny' : 's', 'maxx' : 'e', 'minx' : 'w'}
- bbox = {}
- if self.proj_srs == self.proj_location: # TODO: do it better
- for bbox_item, region_item in bbox_region_items.iteritems():
- bbox[bbox_item] = self.region[region_item]
-
- # if location projection and wms query projection are
- # different, corner points of region are transformed into wms
- # projection and then bbox is created from extreme coordinates
- # of the transformed points
- else:
- for bbox_item, region_item in bbox_region_items.iteritems():
- bbox[bbox_item] = None
- temp_region = self._tempfile()
-
- try:
- temp_region_opened = open(temp_region, 'w')
- temp_region_opened.write("%f %f\n%f %f\n%f %f\n%f %f\n" %\
- (self.region['e'], self.region['n'],\
- self.region['w'], self.region['n'],\
- self.region['w'], self.region['s'],\
- self.region['e'], self.region['s'] ))
- except IOError:
- grass.fatal(_("Unable to write data into tempfile"))
- finally:
- temp_region_opened.close()
-
- points = grass.read_command('m.proj', flags = 'd',
- proj_output = self.proj_srs,
- proj_input = self.proj_location,
- input = temp_region) # TODO: stdin
- grass.try_remove(temp_region)
- if not points:
- grass.fatal(_("Unable to determine region, %s failed") % 'm.proj')
-
- points = points.splitlines()
- if len(points) != 4:
- grass.fatal(_("Region 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 in WMS 1.3.0 is fliped. If self.flip_coords is
- # True, coords in bbox need to be flipped in WMS 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) and self.o_wms_version == "1.3.0":
- self.flip_coords = True
- return bbox
- def _createOutputMap(self):
- """!Import downloaded data into GRASS, reproject data if needed
- using gdalwarp
- """
- # reprojection of raster
- if self.proj_srs != self.proj_location: # TODO: do it better
- grass.message(_("Reprojecting raster..."))
- temp_warpmap = self._tempfile()
-
- if int(os.getenv('GRASS_VERBOSE', '2')) <= 2:
- nuldev = file(os.devnull, 'w+')
- else:
- nuldev = None
-
- # RGB rasters - alpha layer is added for cropping edges of projected raster
- if self.temp_map_bands_num == 3:
- ps = grass.Popen(['gdalwarp',
- '-s_srs', '%s' % self.proj_srs,
- '-t_srs', '%s' % self.proj_location,
- '-r', self.o_method, '-dstalpha',
- self.temp_map, temp_warpmap], stdout = nuldev)
- # RGBA rasters
- else:
- ps = grass.Popen(['gdalwarp',
- '-s_srs', '%s' % self.proj_srs,
- '-t_srs', '%s' % self.proj_location,
- '-r', self.o_method,
- self.temp_map, temp_warpmap], stdout = nuldev)
- ps.wait()
-
- if nuldev:
- nuldev.close()
-
- if ps.returncode != 0:
- grass.fatal(_('%s failed') % 'gdalwarp')
- # raster projection is same as projection of location
- else:
- temp_warpmap = self.temp_map
-
- grass.message(_("Importing raster map into GRASS..."))
- # importing temp_map into GRASS
- if grass.run_command('r.in.gdal',
- quiet = True,
- input = temp_warpmap,
- output = self.o_output) != 0:
- grass.fatal(_('%s failed') % 'r.in.gdal')
-
- # information for destructor to cleanup temp_layers, created
- # with r.in.gdal
- self.cleanup_layers = True
-
- # setting region for full extend of imported raster
- os.environ['GRASS_REGION'] = grass.region_env(rast = self.o_output + '.red')
-
- # mask created from alpha layer, which describes real extend
- # of warped layer (may not be a rectangle), also mask contains
- # transparent parts of raster
- if grass.find_file( self.o_output + '.alpha', element = 'cell', mapset = '.' )['name']:
- # saving current mask (if exists) into temp raster
- if grass.find_file('MASK', element = 'cell', mapset = '.' )['name']:
- if grass.run_command('g.copy',
- quiet = True,
- rast = 'MASK,' + self.o_output + self.original_mask_suffix) != 0:
- grass.fatal(_('%s failed') % 'g.copy')
-
- # info for destructor
- self.cleanup_mask = True
- if grass.run_command('r.mask',
- quiet = True,
- overwrite = True,
- maskcats = "0",
- flags = 'i',
- input = self.o_output + '.alpha') != 0:
- grass.fatal(_('%s failed') % 'r.mask')
-
- if grass.run_command('r.composite',
- quiet = True,
- red = self.o_output + '.red',
- green = self.o_output + '.green',
- blue = self.o_output + '.blue',
- output = self.o_output ) != 0:
- grass.fatal(_('%s failed') % 'r.composite')
-
- grass.try_remove(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 _tempfile(self):
- """!Create temp_file and append list self.temp_files_to_cleanup
- with path of file
-
- @return string path to temp_file
- """
- temp_file = grass.tempfile()
- if temp_file is None:
- grass.fatal(_("Unable to create temporary files"))
-
- # list of created tempfiles for destructor
- self.temp_files_to_cleanup.append(temp_file)
-
- return temp_file
|