def read_from_file(uri: str) -> Tuple[QtXml.QDomDocument, str]: """Read a QGIS project (.qgs and .qgz) from a file path and returns d :param uri: path to the file :type uri: str :return: a tuple with XML document and the filepath. :rtype: Tuple[QtXml.QDomDocument, str] """ doc = QtXml.QDomDocument() file = QFile(uri) if (file.exists() and file.open(QIODevice.ReadOnly | QIODevice.Text) and QFileInfo(file).suffix() == "qgs"): doc.setContent(file) project_path = uri elif file.exists() and (QFileInfo(file).suffix() == "qgz"): temporary_unzip = QTemporaryDir() temporary_unzip.setAutoRemove(False) with zipfile.ZipFile(uri, "r") as zip_ref: zip_ref.extractall(temporary_unzip.path()) project_filename = QDir(temporary_unzip.path()).entryList(["*.qgs"])[0] project_path = os.path.join(temporary_unzip.path(), project_filename) xml = QFile(project_path) if xml.open(QIODevice.ReadOnly | QIODevice.Text): doc.setContent(xml) return doc, project_path
def processAlgorithm(self, parameters, context, feedback): output_file = self.parameterAsFile(parameters, self.OUTPUT, context) # if no project file is specified, we create a temp file from the current project if not output_file: temp_dir = QTemporaryDir() temp_dir.setAutoRemove(False) output_file = os.path.join(temp_dir.path(),'temp_qgis_project') current_project = QgsProject.instance() # store the current path to restore it afterwards current_path = current_project.absoluteFilePath() # store the current use absolute path settings to restore it afterwards current_abs_path_setting = current_project.readBoolEntry('Paths','/Absolute', False)[0] # set use absolute path current_project.writeEntry('Paths','/Absolute', True) # write the project current_project.write(output_file) # retore initial settings current_project.writeEntry('Paths','/Absolute', current_abs_path_setting) current_project.setFileName(current_path) return {self.OUTPUT: output_file}
def read_from_database(uri: str, project_registry) -> Tuple[QtXml.QDomDocument, str]: """Read a QGIS project stored into a (PostgreSQL) database. :param uri: connection string to QGIS project stored into a database. :type uri: str :return: a tuple with XML document and the filepath. :rtype: Tuple[QtXml.QDomDocument, str] """ doc = QtXml.QDomDocument() # uri PG project_storage = project_registry.projectStorageFromUri(uri) temporary_zip = QTemporaryFile() temporary_zip.open() zip_project = temporary_zip.fileName() project_storage.readProject(uri, temporary_zip, QgsReadWriteContext()) temporary_unzip = QTemporaryDir() temporary_unzip.setAutoRemove(False) with zipfile.ZipFile(zip_project, "r") as zip_ref: zip_ref.extractall(temporary_unzip.path()) project_filename = QDir(temporary_unzip.path()).entryList(["*.qgs"])[0] project_path = os.path.join(temporary_unzip.path(), project_filename) xml = QFile(project_path) if xml.open(QIODevice.ReadOnly | QIODevice.Text): doc.setContent(xml) return doc, project_path
def processAlgorithm(self, parameters, context, feedback): # This implementation writes to the project XML directly """ Here is where the processing itself takes place. """ # get the parameter values input_file = self.parameterAsFile(parameters, self.INPUT, context) old_layer_id = self.parameterAsString(parameters, self.OLD_LAYER_ID, context) new_layer = self.parameterAsLayer(parameters, self.NEW_LAYER, context) output_file = self.parameterAsFile(parameters, self.OUTPUT, context) # if the new layer is in memory, we need to save it temporarily somewhere if new_layer.dataProvider().name() == 'memory': t = QTemporaryDir() t.setAutoRemove(False) new_layer_source = os.path.join(t.path(),'t.gpkg') QgsVectorFileWriter.writeAsVectorFormat(new_layer,new_layer_source,"utf8",new_layer.crs(),"GPKG") else: new_layer_source = new_layer.source() tree = et.parse(input_file) root = tree.getroot() # Map Layers nodes = root.findall("projectlayers/maplayer[id='"+old_layer_id+"']/datasource") for node in nodes: node.text = new_layer_source if not nodes: feedback.reportError("No map layer with id {} found".format(old_layer_id)) else: feedback.pushInfo("{} map layers replaced".format(len(nodes))) # Layer tree nodes = root.findall("layer-tree-group/layer-tree-layer[@id='"+old_layer_id+"']") for node in nodes: node.attrib['source'] = new_layer_source feedback.pushInfo("{} layers replaced in the tree".format(len(nodes))) # Legend nodes = root.findall("Layouts/Layout/LayoutItem/layer-tree-group/layer-tree-layer[@id='"+old_layer_id+"']") for node in nodes: node.attrib['source'] = new_layer_source feedback.pushInfo("{} layers replaced in layout legends the tree".format(len(nodes))) tree.write(output_file) # done !! return {self.OUTPUT: output_file}
def processAlgorithm(self, parameters, context, feedback): # Get the parameter values input_source = self.parameterAsSource(parameters, self.INPUT, context) field_date = self.parameterAsString(parameters, self.FIELD_DATE, context) field_pressure = self.parameterAsString(parameters, self.FIELD_PRESSURE, context) field_rmax = self.parameterAsString(parameters, self.FIELD_RMAX, context) date_format = self.parameterAsString(parameters, self.DATE_FORMAT, context) output_wind = self.parameterAsOutputLayer(parameters, self.OUTPUT_WIND, context) output_pressure = self.parameterAsOutputLayer(parameters, self.OUTPUT_PRESSURE, context) # Get the transformation sourceCrs = input_source.sourceCrs() destCrs = QgsCoordinateReferenceSystem(4326) crsTransform = QgsCoordinateTransform(sourceCrs, destCrs, context.transformContext()) # Set input and output folders input_folder = QTemporaryDir() input_folder.setAutoRemove(False) input_folder = input_folder.path() output_folder = QTemporaryDir() output_folder.setAutoRemove(False) output_folder = output_folder.path() # debug input_folder = 'C:\\Users\\Olivier\\Desktop\\testinput' output_folder = 'C:\\Users\\Olivier\\Desktop\\testoutput' # base = os.path.dirname(os.path.abspath(__file__)) # shutil.copy(os.path.join(base,'tcrm.ini'),os.path.join(input_folder,'tcrm.ini')) # shutil.copy(os.path.join(base,'tcrm.csv'),os.path.join(input_folder,'tcrm.csv')) # Load default config and adapt it config = configparser.RawConfigParser() config.read( os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tcrm.ini')) extent = crsTransform.transform(input_source.sourceExtent()) gridLimit = { 'xMin': extent.xMinimum(), 'xMax': extent.xMaximum(), 'yMin': extent.yMinimum(), 'yMax': extent.yMaximum() } config['Region']['gridLimit'] = str(gridLimit) config['Logging']['LogLevel'] = 'DEBUG' config['BDECK']['DateFormat'] = date_format # Write config and CSV to output folder input_ini = os.path.join(input_folder, 'tcrm.ini') ini_file = open(input_ini, 'w') config.write(ini_file) ini_file.close() input_csv = os.path.join(input_folder, 'tcrm.csv') csv_file = open(input_csv, 'w') features = sorted(input_source.getFeatures(), key=lambda f: f.attribute(field_date)) for f in features: point = f.geometry() point.transform(crsTransform) # we write the following columns as configured in ini line = '{skip},{num},{date},{skip},{skip},{lat},{lon},{skip},{pressure},{rmax}\n'.format( skip='SKIP', num=1, date=f.attribute(field_date), lat=point.asPoint().y(), lon=point.asPoint().x(), pressure=f.attribute(field_pressure), rmax=f.attribute(field_rmax), ) csv_file.write(line) csv_file.close() # Run the TCRM model command = self.COMMAND_LINE.format(output_dir=output_folder, input_dir=input_folder, config_file='tcrm.ini') feedback.pushInfo("Running " + command) process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) for line in process.stdout: feedback.pushInfo(line.decode('utf-8')) # Get the output filename output_netcdf = os.path.join(output_folder, 'windfield', 'gust.001-00001.nc') assert (os.path.exists(output_netcdf)) # output_vmax = output_netcdf+'.vmax.tif' # output_slp = output_netcdf+'.slp.tif' # Export the maximum winds command = 'gdal_translate -ot float32 -unscale -CO COMPRESS=deflate NETCDF:"{}":vmax {}'.format( output_netcdf, output_wind) feedback.pushInfo("Running " + command) subprocess.run(command, shell=True) # Export the sea level pressure command = 'gdal_translate -ot float32 -unscale -CO COMPRESS=deflate NETCDF:"{}":slp {}'.format( output_netcdf, output_pressure) feedback.pushInfo("Running " + command) subprocess.run(command, shell=True) QgsMessageLog.logMessage("Done !") return { self.OUTPUT_WIND: output_wind, self.OUTPUT_PRESSURE: output_pressure }