def getDEMForBoundingBox(config, outputDir, outDEMFilename, bbox, srs='EPSG:4326', overwrite=True): """ Extract tile of HYDRO1k digital elevation model (DEM) for bounding box. @param config Python ConfigParser containing the following sections and options: 'GDAL/OGR', 'PATH_OF_GDAL_TRANSLATE' 'HYDRO1k', 'PATH_OF_HYDRO1k_DEM' @param outputDir String representing the absolute/relative path of the directory into which output DEM should be written @param outDEMFilename String representing the name of the DEM file to be written @param bbox Dict representing the lat/long coordinates and spatial reference of the bounding box area for which the DEM is to be extracted. The following keys must be specified: minX, minY, maxX, maxY, srs. @param srs String representing the spatial reference of the raster to be returned. @param overwrite Boolean value indicating whether or not the file indicated by filename should be overwritten. If False and filename exists, IOError exception will be thrown with errno.EEXIST @return True if DEM tile was created and False if not. """ tileCreated = False assert ('minX' in bbox) assert ('minY' in bbox) assert ('maxX' in bbox) assert ('maxY' in bbox) assert ('srs' in bbox) if not os.path.isdir(outputDir): raise IOError(errno.ENOTDIR, "Output directory %s is not a directory" % (outputDir, )) if not os.access(outputDir, os.W_OK): raise IOError( errno.EACCES, "Not allowed to write to output directory %s" % (outputDir, )) outputDir = os.path.abspath(outputDir) outDEMFilepath = os.path.join(outputDir, outDEMFilename) if os.path.exists(outDEMFilepath): if overwrite: deleteGeoTiff(outDEMFilepath) else: raise IOError(errno.EEXIST, "DEM file %s already exists" % outDEMFilepath) hydro1kDEMFilePath = config.get('HYDRO1k', 'PATH_OF_HYDRO1k_DEM') if not os.access(hydro1kDEMFilePath, os.R_OK): raise IOError( errno.EACCES, "Unable to read HYDRO1k DEM located at %s" % (hydro1kDEMFilePath, )) extractTileFromRaster(config, outputDir, hydro1kDEMFilePath, outDEMFilepath, bbox) tileCreated = os.path.exists(outDEMFilepath) return tileCreated
def deleteSoilRasters(context, manifest): """ Delete soil raster maps stored in a project @param context Context object containing projectDir, the path of the project whose metadata store is to be read from @param manifest Dict containing manifest entries. Files associted with entries whose key begins with 'soil_raster_' will be deleted """ for entry in list(manifest.keys()): if entry.find('soil_raster_') == 0: filePath = os.path.join(context.projectDir, manifest[entry]) deleteGeoTiff(filePath)
def getDEMForBoundingBox(config, outputDir, outDEMFilename, bbox, srs='EPSG:4326', overwrite=True): """ Extract tile of HYDRO1k digital elevation model (DEM) for bounding box. @param config Python ConfigParser containing the following sections and options: 'GDAL/OGR', 'PATH_OF_GDAL_TRANSLATE' 'HYDRO1k', 'PATH_OF_HYDRO1k_DEM' @param outputDir String representing the absolute/relative path of the directory into which output DEM should be written @param outDEMFilename String representing the name of the DEM file to be written @param bbox Dict representing the lat/long coordinates and spatial reference of the bounding box area for which the DEM is to be extracted. The following keys must be specified: minX, minY, maxX, maxY, srs. @param srs String representing the spatial reference of the raster to be returned. @param overwrite Boolean value indicating whether or not the file indicated by filename should be overwritten. If False and filename exists, IOError exception will be thrown with errno.EEXIST @return True if DEM tile was created and False if not. """ tileCreated = False assert('minX' in bbox) assert('minY' in bbox) assert('maxX' in bbox) assert('maxY' in bbox) assert('srs' in bbox) if not os.path.isdir(outputDir): raise IOError(errno.ENOTDIR, "Output directory %s is not a directory" % (outputDir,)) if not os.access(outputDir, os.W_OK): raise IOError(errno.EACCES, "Not allowed to write to output directory %s" % (outputDir,)) outputDir = os.path.abspath(outputDir) outDEMFilepath = os.path.join(outputDir, outDEMFilename) if os.path.exists(outDEMFilepath): if overwrite: deleteGeoTiff(outDEMFilepath) else: raise IOError(errno.EEXIST, "DEM file %s already exists" % outDEMFilepath) hydro1kDEMFilePath = config.get('HYDRO1k', 'PATH_OF_HYDRO1k_DEM') if not os.access(hydro1kDEMFilePath, os.R_OK): raise IOError(errno.EACCES, "Unable to read HYDRO1k DEM located at %s" % (hydro1kDEMFilePath,)) extractTileFromRaster(config, outputDir, hydro1kDEMFilePath, outDEMFilepath, bbox) tileCreated = os.path.exists(outDEMFilepath) return tileCreated
def getDEMForBoundingBox(config, outputDir, outFilename, bbox, srs, coverage=DEFAULT_COVERAGE, resx=None, resy=None, interpolation=DEFAULT_RASTER_RESAMPLE_METHOD, scale=1.0, overwrite=True, verbose=False, outfp=sys.stdout): """ Fetch U.S. 1/3 arcsecond DEM data hosted by U.S. Geological Survey using OGC WCS 1.1.1 query. @note Adapted from code provided by [email protected]. @param config A Python ConfigParser (not currently used) @param outputDir String representing the absolute/relative path of the directory into which output raster should be written @param outFilename String representing the name of the raster file to be written @param bbox Dict representing the lat/long coordinates and spatial reference of the bounding box area for which the raster is to be extracted. The following keys must be specified: minX, minY, maxX, maxY, srs. @param srs String representing the spatial reference of the raster to be returned. @param coverage String representing the raster source from which to get the raster coverage. Must be one of: NHDPlus_hydroDEM, NED @param resx Float representing the X resolution of the raster(s) to be returned @param resy Float representing the Y resolution of the raster(s) to be returned @param interpolation String representing interpolation method. Must be one of RASTER_RESAMPLE_METHOD. Defaults to DEFAULT_RASTER_RESAMPLE_METHOD. @param scale Float representing factor by which to scale elevation data. Defaults to 1.0. @param overwrite Boolean value indicating whether or not the file indicated by filename should be overwritten. If False and filename exists, IOError exception will be thrown with errno.EEXIST @param verbose Boolean True if detailed output information should be printed to outfp @param outfp File-like object to which verbose output should be printed @raise IOError if outputDir is not a writable directory @raise IOError if outFilename already exists and overwrite is False (see above) @raise Exception if there was an error making the WCS request @return Tuple(True if raster data were fetched and False if not, URL of raster fetched) """ dataFetched = False assert(coverage in COVERAGES.keys()) assert('minX' in bbox) assert('minY' in bbox) assert('maxX' in bbox) assert('maxY' in bbox) assert('srs' in bbox) assert(scale > 0.0) if not os.path.isdir(outputDir): raise IOError(errno.ENOTDIR, "Output directory %s is not a directory" % (outputDir,)) if not os.access(outputDir, os.W_OK): raise IOError(errno.EACCES, "Not allowed to write to output directory %s" % (outputDir,)) outputDir = os.path.abspath(outputDir) outFilepath = os.path.join(outputDir, outFilename) deleteOldfile = False if os.path.exists(outFilepath): if overwrite: deleteOldfile = True else: raise IOError(errno.EEXIST, "Raster file %s already exists" % outFilepath) cov = COVERAGES[coverage] grid_origin = cov['grid_origin'] grid_offset = cov['grid_offset'] grid_extent = cov['grid_extent'] s_srs = cov['srs'] if resx is None: resx = abs(grid_offset[0]) if resy is None: resy = abs(grid_offset[1]) t_srs = srs # For requests, grid cell centers are used. Need to add half the grid_offset to the grid_origin grid_origin_0 = grid_origin[0] + grid_offset[0] / 2.0 grid_origin_1 = grid_origin[1] + grid_offset[1] / 2.0 p = Proj(init=DEFAULT_SRS) (x1, y1) = p(bbox['minX'], bbox['minY']) (x2, y2) = p(bbox['maxX'], bbox['maxY']) # Pad the width of the bounding box as the Albers transform results in regions of interest # that are a bit narrower than I would like, which risks watershed boundaries lying beyond # the DEM boundary. len_x = x2 - x1 del_x = len_x * 0.30 x1 = x1 - del_x x2 = x2 + del_x bbox_srs = DEFAULT_SRS # Find the number of grid cells from the grid origin to each edge of the request. # Multiply by the grid_offset and add the grid origin to get to the request location. xi1 = floor((x1 - grid_origin_0) / grid_offset[0]) * grid_offset[0] + grid_origin_0 xi2 = ceil((x2 - grid_origin_0) / grid_offset[0]) * grid_offset[0] + grid_origin_0 yi1 = floor((y1 - grid_origin_1) / grid_offset[1]) * grid_offset[1] + grid_origin_1 yi2 = ceil((y2 - grid_origin_1) / grid_offset[1]) * grid_offset[1] + grid_origin_1 # coverage, crs, bbox, format. May have the following fields: response_srs, store, resx, resy, interpolation url = URL_PROTO.format(coverage=coverage, x1=xi1, y1=yi1, x2=xi2, y2=yi2, bbox_srs=bbox_srs, xoffset=grid_offset[0], yoffset=grid_offset[1]) #ORG urlFetched = "http://%s%s" % (HOST, url) urlFetched = "https://%s%s" % (HOST, url) if verbose: outfp.write("Acquiring DEM data from {0} ...\n".format(urlFetched)) # Make initial request, which will return the URL of our clipped coverage r = requests.get(urlFetched) if r.status_code != 200: raise Exception("Error fetching {url}, HTTP status code was {code} {reason}".format(urlFetched, r.status_code, r.reason)) usgs_dem_coverage_handler = USGSDEMCoverageHandler() xml.sax.parseString(r.text, usgs_dem_coverage_handler) coverage_url = usgs_dem_coverage_handler.coverage_url if coverage_url is None: raise Exception("Unable to deteremine coverage URL from WCS server response. Response text was: {0}".format(r.text)) parsed_coverage_url = urlparse.urlparse(coverage_url) if verbose: outfp.write("Downloading DEM coverage from {0} ...\n".format(coverage_url)) # Download coverage to tempfile tmp_dir = tempfile.mkdtemp() tmp_cov_name = os.path.join(tmp_dir, 'usgswcsdemtmp') tmp_out = open(tmp_cov_name, mode='w+b') #ORG conn = httplib.HTTPConnection(parsed_coverage_url.netloc) conn = httplib.HTTPSConnection(parsed_coverage_url.netloc) try: conn.request('GET', parsed_coverage_url.path) res = conn.getresponse(buffering=True) except socket.error as e: msg = "Encountered the following error when trying to read raster from %s. Error: %s. Please try again later or contact the developer." % \ (urlFetched, str(e) ) raise Exception(msg) if 200 != res.status: msg = "HTTP response %d %s encountered when querying %s. Please try again later or contact the developer." % \ (res.status, res.reason, urlFetched) raise Exception(msg) contentType = res.getheader('Content-Type') mimeType = 'image/tiff' if contentType.startswith(mimeType): # The data returned were of the type expected, read the data data = res.read(_BUFF_LEN) if data: dataFetched = True while data: tmp_out.write(data) data = res.read(_BUFF_LEN) tmp_out.close() elif contentType.startswith(CONTENT_TYPE_ERRORS): # Read the error and print to stderr msg = "The following error was encountered reading WCS coverage URL %s\n\n" %\ (coverage_url, ) data = res.read(_BUFF_LEN) while data: msg += data raise Exception(msg) else: msg = "Query for raster from URL %s returned content type %s, was expecting type %s. " + \ " Operation failed." % \ (coverage_url, contentType, mimeType) raise Exception(msg) # Rescale raster values if requested if scale != 1.0: # Rescale values in raster if verbose: outfp.write("Rescaling raster values by factor {0}".format(scale)) rescale_out = os.path.basename("{0}_rescale".format(tmp_cov_name)) rescaleRaster(config, tmp_dir, tmp_cov_name, rescale_out, scale) tmp_cov_name = os.path.join(tmp_dir, rescale_out) if deleteOldfile: deleteGeoTiff(outFilepath) if verbose: msg = "Resampling raster from {s_srs} to {t_srs} " + \ "with X resolution {resx} and Y resolution {resy}\n" outfp.write(msg.format(s_srs=s_srs, t_srs=t_srs, resx=resx, resy=resy)) # Re-sample to target spatial reference and resolution resampleRaster(config, outputDir, tmp_cov_name, outFilename, s_srs, t_srs, resx, resy, interpolation) # Delete temp directory shutil.rmtree(tmp_dir) return ( dataFetched, urlFetched )
trX=demResolutionX, trY=demResolutionY) sys.stdout.write('done\n') else: shutil.move(tmpDEMFilepath, demFilepath) # Write metadata GenericMetadata.writeStudyAreaEntry(context, 'dem_res_x', demResolutionX) GenericMetadata.writeStudyAreaEntry(context, 'dem_res_y', demResolutionY) GenericMetadata.writeStudyAreaEntry(context, 'dem_srs', t_srs) # Get rows and columns for DEM (columns, rows) = getDimensionsForRaster(demFilepath) GenericMetadata.writeStudyAreaEntry(context, 'dem_columns', columns) GenericMetadata.writeStudyAreaEntry(context, 'dem_rows', rows) # Write provenance asset = AssetProvenance(GenericMetadata.MANIFEST_SECTION) asset.name = 'dem' asset.dcIdentifier = demFilename asset.dcSource = demURL asset.dcTitle = 'Digital Elevation Model' asset.dcPublisher = 'GeoBrain' asset.dcDescription = cmdline asset.writeToMetadata(context) # Write processing history GenericMetadata.appendProcessingHistoryItem(context, cmdline) # Clean-up deleteGeoTiff(tmpDEMFilepath)
def getDEMForBoundingBox(config, outputDir, outFilename, bbox, srs, coverage=DEFAULT_COVERAGE, resx=None, resy=None, interpolation=DEFAULT_RASTER_RESAMPLE_METHOD, scale=1.0, overwrite=True, verbose=False, outfp=sys.stdout): """ Fetch U.S. 1/3 arcsecond DEM data hosted by U.S. Geological Survey using OGC WCS 1.1.1 query. @note Adapted from code provided by [email protected]. @param config A Python ConfigParser (not currently used) @param outputDir String representing the absolute/relative path of the directory into which output raster should be written @param outFilename String representing the name of the raster file to be written @param bbox Dict representing the lat/long coordinates and spatial reference of the bounding box area for which the raster is to be extracted. The following keys must be specified: minX, minY, maxX, maxY, srs. @param srs String representing the spatial reference of the raster to be returned. @param coverage String representing the raster source from which to get the raster coverage. Must be one of: NHDPlus_hydroDEM, NED @param resx Float representing the X resolution of the raster(s) to be returned @param resy Float representing the Y resolution of the raster(s) to be returned @param interpolation String representing interpolation method. Must be one of RASTER_RESAMPLE_METHOD. Defaults to DEFAULT_RASTER_RESAMPLE_METHOD. @param scale Float representing factor by which to scale elevation data. Defaults to 1.0. @param overwrite Boolean value indicating whether or not the file indicated by filename should be overwritten. If False and filename exists, IOError exception will be thrown with errno.EEXIST @param verbose Boolean True if detailed output information should be printed to outfp @param outfp File-like object to which verbose output should be printed @raise IOError if outputDir is not a writable directory @raise IOError if outFilename already exists and overwrite is False (see above) @raise Exception if there was an error making the WCS request @return Tuple(True if raster data were fetched and False if not, URL of raster fetched) """ dataFetched = False assert (coverage in list(COVERAGES.keys())) assert ('minX' in bbox) assert ('minY' in bbox) assert ('maxX' in bbox) assert ('maxY' in bbox) assert ('srs' in bbox) assert (scale > 0.0) if not os.path.isdir(outputDir): raise IOError(errno.ENOTDIR, "Output directory %s is not a directory" % (outputDir, )) if not os.access(outputDir, os.W_OK): raise IOError( errno.EACCES, "Not allowed to write to output directory %s" % (outputDir, )) outputDir = os.path.abspath(outputDir) outFilepath = os.path.join(outputDir, outFilename) deleteOldfile = False if os.path.exists(outFilepath): if overwrite: deleteOldfile = True else: raise IOError(errno.EEXIST, "Raster file %s already exists" % outFilepath) cov = COVERAGES[coverage] grid_origin = cov['grid_origin'] grid_offset = cov['grid_offset'] grid_extent = cov['grid_extent'] s_srs = cov['srs'] if resx is None: resx = abs(grid_offset[0]) if resy is None: resy = abs(grid_offset[1]) t_srs = srs # For requests, grid cell centers are used. Need to add half the grid_offset to the grid_origin grid_origin_0 = grid_origin[0] + grid_offset[0] / 2.0 grid_origin_1 = grid_origin[1] + grid_offset[1] / 2.0 p = Proj(init=DEFAULT_SRS) (x1, y1) = p(bbox['minX'], bbox['minY']) (x2, y2) = p(bbox['maxX'], bbox['maxY']) # Pad the width of the bounding box as the Albers transform results in regions of interest # that are a bit narrower than I would like, which risks watershed boundaries lying beyond # the DEM boundary. len_x = x2 - x1 del_x = len_x * 0.30 x1 = x1 - del_x x2 = x2 + del_x bbox_srs = DEFAULT_SRS # Find the number of grid cells from the grid origin to each edge of the request. # Multiply by the grid_offset and add the grid origin to get to the request location. xi1 = floor( (x1 - grid_origin_0) / grid_offset[0]) * grid_offset[0] + grid_origin_0 xi2 = ceil( (x2 - grid_origin_0) / grid_offset[0]) * grid_offset[0] + grid_origin_0 yi1 = floor( (y1 - grid_origin_1) / grid_offset[1]) * grid_offset[1] + grid_origin_1 yi2 = ceil( (y2 - grid_origin_1) / grid_offset[1]) * grid_offset[1] + grid_origin_1 # coverage, crs, bbox, format. May have the following fields: response_srs, store, resx, resy, interpolation url = URL_PROTO.format(coverage=coverage, x1=xi1, y1=yi1, x2=xi2, y2=yi2, bbox_srs=bbox_srs, xoffset=grid_offset[0], yoffset=grid_offset[1]) #ORG urlFetched = "http://%s%s" % (HOST, url) urlFetched = "https://%s%s" % (HOST, url) if verbose: outfp.write("Acquiring DEM data from {0} ...\n".format(urlFetched)) # Make initial request, which will return the URL of our clipped coverage r = requests.get(urlFetched) if r.status_code != 200: raise Exception( "Error fetching {url}, HTTP status code was {code} {reason}". format(urlFetched, r.status_code, r.reason)) usgs_dem_coverage_handler = USGSDEMCoverageHandler() xml.sax.parseString(r.text, usgs_dem_coverage_handler) coverage_url = usgs_dem_coverage_handler.coverage_url if coverage_url is None: raise Exception( "Unable to deteremine coverage URL from WCS server response. Response text was: {0}" .format(r.text)) parsed_coverage_url = urllib.parse.urlparse(coverage_url) if verbose: outfp.write( "Downloading DEM coverage from {0} ...\n".format(coverage_url)) # Download coverage to tempfile tmp_dir = tempfile.mkdtemp() tmp_cov_name = os.path.join(tmp_dir, 'usgswcsdemtmp') tmp_out = open(tmp_cov_name, mode='w+b') #ORG conn = httplib.HTTPConnection(parsed_coverage_url.netloc) conn = http.client.HTTPSConnection(parsed_coverage_url.netloc) try: conn.request('GET', parsed_coverage_url.path) res = conn.getresponse(buffering=True) except socket.error as e: msg = "Encountered the following error when trying to read raster from %s. Error: %s. Please try again later or contact the developer." % \ (urlFetched, str(e) ) raise Exception(msg) if 200 != res.status: msg = "HTTP response %d %s encountered when querying %s. Please try again later or contact the developer." % \ (res.status, res.reason, urlFetched) raise Exception(msg) contentType = res.getheader('Content-Type') mimeType = 'image/tiff' if contentType.startswith(mimeType): # The data returned were of the type expected, read the data data = res.read(_BUFF_LEN) if data: dataFetched = True while data: tmp_out.write(data) data = res.read(_BUFF_LEN) tmp_out.close() elif contentType.startswith(CONTENT_TYPE_ERRORS): # Read the error and print to stderr msg = "The following error was encountered reading WCS coverage URL %s\n\n" %\ (coverage_url, ) data = res.read(_BUFF_LEN) while data: msg += data raise Exception(msg) else: msg = "Query for raster from URL %s returned content type %s, was expecting type %s. " + \ " Operation failed." % \ (coverage_url, contentType, mimeType) raise Exception(msg) # Rescale raster values if requested if scale != 1.0: # Rescale values in raster if verbose: outfp.write("Rescaling raster values by factor {0}".format(scale)) rescale_out = os.path.basename("{0}_rescale".format(tmp_cov_name)) rescaleRaster(config, tmp_dir, tmp_cov_name, rescale_out, scale) tmp_cov_name = os.path.join(tmp_dir, rescale_out) if deleteOldfile: deleteGeoTiff(outFilepath) if verbose: msg = "Resampling raster from {s_srs} to {t_srs} " + \ "with X resolution {resx} and Y resolution {resy}\n" outfp.write(msg.format(s_srs=s_srs, t_srs=t_srs, resx=resx, resy=resy)) # Re-sample to target spatial reference and resolution resampleRaster(config, outputDir, tmp_cov_name, outFilename, s_srs, t_srs, resx, resy, interpolation) # Delete temp directory shutil.rmtree(tmp_dir) return (dataFetched, urlFetched)
trX=demResolutionX, trY=demResolutionY) sys.stdout.write('done\n') else: shutil.move(tmpDEMFilepath, demFilepath) # Write metadata GenericMetadata.writeStudyAreaEntry(context, 'dem_res_x', demResolutionX) GenericMetadata.writeStudyAreaEntry(context, 'dem_res_y', demResolutionY) GenericMetadata.writeStudyAreaEntry(context, 'dem_srs', t_srs) # Get rows and columns for DEM (columns, rows) = getDimensionsForRaster(demFilepath) GenericMetadata.writeStudyAreaEntry(context, 'dem_columns', columns) GenericMetadata.writeStudyAreaEntry(context, 'dem_rows', rows) # Write provenance asset = AssetProvenance(GenericMetadata.MANIFEST_SECTION) asset.name = 'dem' asset.dcIdentifier = demFilename asset.dcSource = demURL asset.dcTitle = demwcs.COVERAGE_DESC[args.demType] asset.dcPublisher = 'Geoscience Australia' asset.dcDescription = cmdline asset.writeToMetadata(context) # Write processing history GenericMetadata.appendProcessingHistoryItem(context, cmdline) # Clean-up deleteGeoTiff(tmpDEMFilepath)
def getRasterForBoundingBox(config, outputDir, outFilename, host, urlProto, mimeType, bbox, coverage, srs, format, response_crs=None, store=None, resx=None, resy=None, interpolation=None, overwrite=True): """ Fetch a rater from WCS-compliant web service. Will write any error returned by query to sys.stderr. @param config A Python ConfigParser (not currently used) @param outputDir String representing the absolute/relative path of the directory into which output raster should be written @param outFilename String representing the name of the raster file to be written @param host String representing the host (e.g. 'webmap.ornl.gov', 'geobrain.laits.gmu.edu') @param urlProto String representing WCS service URL, must contain the following replacement fields: coverage, crs, bbox, format. May have the following fields: response_srs, store, resx, resy, interpolation @param mimeType String representing the MIME type expected for the response data @param bbox Dict representing the lat/long coordinates and spatial reference of the bounding box area for which the raster is to be extracted. The following keys must be specified: minX, minY, maxX, maxY, srs. @param coverage String representing the raster source from which to get the raster coverage. Must be a value listed in SUPPORTED_COVERAGE @param srs String representing the spatial reference of the raster to be returned. @param format String representing the MIME type of the raster format to be returned. Must be a value listed in SUPPORTED_FORMATS @param response_srs String representing the spatial reference of the raster to be returned. Present for compatibility purposes and is ignored; only srs is used. @param store String present for compatibility with WCS4DEM. @param resx Float representing the X resolution of the raster(s) to be returned @param resy Float representing the Y resolution of the raster(s) to be returned @param interpolation String representing interpolation method. @param overwrite Boolean value indicating whether or not the file indicated by filename should be overwritten. If False and filename exists, IOError exception will be thrown with errno.EEXIST @raise IOError if outputDir is not a writable directory @raise IOError if outFilename already exists and overwrite is False (see above) @return Tuple(True if raster data were fetched and False if not, URL of raster fetched) """ dataFetched = False assert(format) assert(coverage) assert('minX' in bbox) assert('minY' in bbox) assert('maxX' in bbox) assert('maxY' in bbox) assert('srs' in bbox) if not os.path.isdir(outputDir): raise IOError(errno.ENOTDIR, "Output directory %s is not a directory" % (outputDir,)) if not os.access(outputDir, os.W_OK): raise IOError(errno.EACCES, "Not allowed to write to output directory %s" % (outputDir,)) outputDir = os.path.abspath(outputDir) outFilepath = os.path.join(outputDir, outFilename) if os.path.exists(outFilepath): if overwrite: deleteGeoTiff(outFilepath) else: raise IOError(errno.EEXIST, "Raster file %s already exists" % outFilepath) crs = bbox['srs'] bboxStr = "%f,%f,%f,%f" % (bbox['minX'], bbox['minY'], bbox['maxX'], bbox['maxY']) # coverage, crs, bbox, format. May have the following fields: response_srs, store, resx, resy, interpolation url = urlProto.format(coverage=coverage, crs=crs, bbox=bboxStr, format=format, response_crs=srs, store=store, resx=resx, resy=resy, interpolation=interpolation) urlFetched = "http://%s%s" % (host, url) conn = httplib.HTTPConnection(host) try: conn.request('GET', url) res = conn.getresponse(buffering=True) except socket.error as e: msg = "Encountered the following error when trying to read raster from %s. Error: %s. Please try again later or contact the developer." % \ (urlFetched, str(e) ) sys.stderr.write( textwrap.fill(msg) ) return ( dataFetched, urlFetched ) if 200 != res.status: msg = "HTTP response %d %s encountered when querying %s. Please try again later or contact the developer." % \ (res.status, res.reason, urlFetched) sys.stderr.write( textwrap.fill(msg) ) return ( dataFetched, urlFetched ) contentType = res.getheader('Content-Type') if contentType == mimeType: # The data returned were of the type expected, read the data data = res.read(_BUFF_LEN) if data: demOut = open(outFilepath, 'wb') dataFetched = True while data: demOut.write(data) data = res.read(_BUFF_LEN) demOut.close() elif contentType in CONTENT_TYPE_ERRORS: # Read the error and print to stderr msg = "The following error was encountered reading URL %s\n" %\ (urlFetched, ) sys.stderr.write( textwrap.fill(msg) ) data = res.read(_BUFF_LEN) while data: sys.stderr.write(data) sys.stderr.flush() data = res.read(_BUFF_LEN) sys.stderr.write('\n') else: msg = "Query for raster from URL %s returned content type %s, was expecting type %s. Operation failed." % \ (urlFetched, contentType, mimeType) sys.stderr.write( textwrap.fill(msg) ) return ( dataFetched, urlFetched )
def getRasterForBoundingBox(config, outputDir, outFilename, host, urlProto, mimeType, bbox, coverage, srs, format, response_crs=None, store=None, resx=None, resy=None, interpolation=None, overwrite=True): """ Fetch a rater from WCS-compliant web service. Will write any error returned by query to sys.stderr. @param config A Python ConfigParser (not currently used) @param outputDir String representing the absolute/relative path of the directory into which output raster should be written @param outFilename String representing the name of the raster file to be written @param host String representing the host (e.g. 'webmap.ornl.gov', 'geobrain.laits.gmu.edu') @param urlProto String representing WCS service URL, must contain the following replacement fields: coverage, crs, bbox, format. May have the following fields: response_srs, store, resx, resy, interpolation @param mimeType String representing the MIME type expected for the response data @param bbox Dict representing the lat/long coordinates and spatial reference of the bounding box area for which the raster is to be extracted. The following keys must be specified: minX, minY, maxX, maxY, srs. @param coverage String representing the raster source from which to get the raster coverage. Must be a value listed in SUPPORTED_COVERAGE @param srs String representing the spatial reference of the raster to be returned. @param format String representing the MIME type of the raster format to be returned. Must be a value listed in SUPPORTED_FORMATS @param response_srs String representing the spatial reference of the raster to be returned. Present for compatibility purposes and is ignored; only srs is used. @param store String present for compatibility with WCS4DEM. @param resx Float representing the X resolution of the raster(s) to be returned @param resy Float representing the Y resolution of the raster(s) to be returned @param interpolation String representing interpolation method. @param overwrite Boolean value indicating whether or not the file indicated by filename should be overwritten. If False and filename exists, IOError exception will be thrown with errno.EEXIST @raise IOError if outputDir is not a writable directory @raise IOError if outFilename already exists and overwrite is False (see above) @return Tuple(True if raster data were fetched and False if not, URL of raster fetched) """ dataFetched = False assert (format) assert (coverage) assert ('minX' in bbox) assert ('minY' in bbox) assert ('maxX' in bbox) assert ('maxY' in bbox) assert ('srs' in bbox) if not os.path.isdir(outputDir): raise IOError(errno.ENOTDIR, "Output directory %s is not a directory" % (outputDir, )) if not os.access(outputDir, os.W_OK): raise IOError( errno.EACCES, "Not allowed to write to output directory %s" % (outputDir, )) outputDir = os.path.abspath(outputDir) outFilepath = os.path.join(outputDir, outFilename) if os.path.exists(outFilepath): if overwrite: deleteGeoTiff(outFilepath) else: raise IOError(errno.EEXIST, "Raster file %s already exists" % outFilepath) crs = bbox['srs'] bboxStr = "%f,%f,%f,%f" % (bbox['minX'], bbox['minY'], bbox['maxX'], bbox['maxY']) # coverage, crs, bbox, format. May have the following fields: response_srs, store, resx, resy, interpolation url = urlProto.format(coverage=coverage, crs=crs, bbox=bboxStr, format=format, response_crs=srs, store=store, resx=resx, resy=resy, interpolation=interpolation) urlFetched = "http://%s%s" % (host, url) conn = http.client.HTTPConnection(host) try: conn.request('GET', url) res = conn.getresponse(buffering=True) except socket.error as e: msg = "Encountered the following error when trying to read raster from %s. Error: %s. Please try again later or contact the developer." % \ (urlFetched, str(e) ) sys.stderr.write(textwrap.fill(msg)) return (dataFetched, urlFetched) if 200 != res.status: msg = "HTTP response %d %s encountered when querying %s. Please try again later or contact the developer." % \ (res.status, res.reason, urlFetched) sys.stderr.write(textwrap.fill(msg)) return (dataFetched, urlFetched) contentType = res.getheader('Content-Type') if contentType == mimeType: # The data returned were of the type expected, read the data data = res.read(_BUFF_LEN) if data: demOut = open(outFilepath, 'wb') dataFetched = True while data: demOut.write(data) data = res.read(_BUFF_LEN) demOut.close() elif contentType in CONTENT_TYPE_ERRORS: # Read the error and print to stderr msg = "The following error was encountered reading URL %s\n" %\ (urlFetched, ) sys.stderr.write(textwrap.fill(msg)) data = res.read(_BUFF_LEN) while data: sys.stderr.write(data) sys.stderr.flush() data = res.read(_BUFF_LEN) sys.stderr.write('\n') else: msg = "Query for raster from URL %s returned content type %s, was expecting type %s. Operation failed." % \ (urlFetched, contentType, mimeType) sys.stderr.write(textwrap.fill(msg)) return (dataFetched, urlFetched)